diff options
| author | Albert Lee <albertcc@tw.ibm.com> | 2007-02-16 20:40:21 -0500 |
|---|---|---|
| committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-02-16 20:40:21 -0500 |
| commit | f0dd8712eb8cc5687b4582fbc41cfbcd55bba0d2 (patch) | |
| tree | 190bc6cf68e056ae72d895dc2c9074de2c0ed18f /drivers | |
| parent | fdb77da4ca68ae17a39d58c9d5c00479a7e124c0 (diff) | |
ide: clear bmdma status in ide_intr() for ICHx controllers (revised #4)
patch 1/2 (revised):
- Fix drive->waiting_for_dma to work with CDB-intr devices.
- Do the dma status clearing in ide_intr() and add a new
hwif->ide_dma_clear_irq for Intel ICHx controllers.
Revised per Alan, Sergei and Bart's advice.
Patch against 2.6.20-rc6. Tested ok on my ICH4 and pdc20275 adapters.
Please review/apply, thanks.
Signed-off-by: Albert Lee <albertcc@tw.ibm.com>
Cc: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: "Adam W. Hawks" <awhawks@us.ibm.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/ide/ide-cd.c | 8 | ||||
| -rw-r--r-- | drivers/ide/ide-io.c | 11 | ||||
| -rw-r--r-- | drivers/ide/ide.c | 1 | ||||
| -rw-r--r-- | drivers/ide/pci/piix.c | 63 |
4 files changed, 68 insertions, 15 deletions
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 5969cec58dc1..21f4ae2b7176 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c | |||
| @@ -930,6 +930,10 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive, | |||
| 930 | HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); | 930 | HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); |
| 931 | 931 | ||
| 932 | if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { | 932 | if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { |
| 933 | /* waiting for CDB interrupt, not DMA yet. */ | ||
| 934 | if (info->dma) | ||
| 935 | drive->waiting_for_dma = 0; | ||
| 936 | |||
| 933 | /* packet command */ | 937 | /* packet command */ |
| 934 | ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry); | 938 | ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry); |
| 935 | return ide_started; | 939 | return ide_started; |
| @@ -972,6 +976,10 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive, | |||
| 972 | /* Check for errors. */ | 976 | /* Check for errors. */ |
| 973 | if (cdrom_decode_status(drive, DRQ_STAT, NULL)) | 977 | if (cdrom_decode_status(drive, DRQ_STAT, NULL)) |
| 974 | return ide_stopped; | 978 | return ide_stopped; |
| 979 | |||
| 980 | /* Ok, next interrupt will be DMA interrupt. */ | ||
| 981 | if (info->dma) | ||
| 982 | drive->waiting_for_dma = 1; | ||
| 975 | } else { | 983 | } else { |
| 976 | /* Otherwise, we must wait for DRQ to get set. */ | 984 | /* Otherwise, we must wait for DRQ to get set. */ |
| 977 | if (ide_wait_stat(&startstop, drive, DRQ_STAT, | 985 | if (ide_wait_stat(&startstop, drive, DRQ_STAT, |
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 2614f41b5074..99d1c43f433e 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c | |||
| @@ -1646,6 +1646,17 @@ irqreturn_t ide_intr (int irq, void *dev_id) | |||
| 1646 | del_timer(&hwgroup->timer); | 1646 | del_timer(&hwgroup->timer); |
| 1647 | spin_unlock(&ide_lock); | 1647 | spin_unlock(&ide_lock); |
| 1648 | 1648 | ||
| 1649 | /* Some controllers might set DMA INTR no matter DMA or PIO; | ||
| 1650 | * bmdma status might need to be cleared even for | ||
| 1651 | * PIO interrupts to prevent spurious/lost irq. | ||
| 1652 | */ | ||
| 1653 | if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma)) | ||
| 1654 | /* ide_dma_end() needs bmdma status for error checking. | ||
| 1655 | * So, skip clearing bmdma status here and leave it | ||
| 1656 | * to ide_dma_end() if this is dma interrupt. | ||
| 1657 | */ | ||
| 1658 | hwif->ide_dma_clear_irq(drive); | ||
| 1659 | |||
| 1649 | if (drive->unmask) | 1660 | if (drive->unmask) |
| 1650 | local_irq_enable_in_hardirq(); | 1661 | local_irq_enable_in_hardirq(); |
| 1651 | /* service this interrupt, may set handler for next interrupt */ | 1662 | /* service this interrupt, may set handler for next interrupt */ |
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index c750f6ce770a..65eb095469b5 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c | |||
| @@ -509,6 +509,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif) | |||
| 509 | hwif->ide_dma_on = tmp_hwif->ide_dma_on; | 509 | hwif->ide_dma_on = tmp_hwif->ide_dma_on; |
| 510 | hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly; | 510 | hwif->ide_dma_off_quietly = tmp_hwif->ide_dma_off_quietly; |
| 511 | hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; | 511 | hwif->ide_dma_test_irq = tmp_hwif->ide_dma_test_irq; |
| 512 | hwif->ide_dma_clear_irq = tmp_hwif->ide_dma_clear_irq; | ||
| 512 | hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on; | 513 | hwif->ide_dma_host_on = tmp_hwif->ide_dma_host_on; |
| 513 | hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off; | 514 | hwif->ide_dma_host_off = tmp_hwif->ide_dma_host_off; |
| 514 | hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq; | 515 | hwif->ide_dma_lostirq = tmp_hwif->ide_dma_lostirq; |
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c index 52cfc2ac22c1..af65b0888bbb 100644 --- a/drivers/ide/pci/piix.c +++ b/drivers/ide/pci/piix.c | |||
| @@ -410,17 +410,14 @@ fast_ata_pio: | |||
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | /** | 412 | /** |
| 413 | * init_chipset_piix - set up the PIIX chipset | 413 | * piix_is_ichx - check if ICHx |
| 414 | * @dev: PCI device to set up | 414 | * @dev: PCI device to check |
| 415 | * @name: Name of the device | ||
| 416 | * | 415 | * |
| 417 | * Initialize the PCI device as required. For the PIIX this turns | 416 | * returns 1 if ICHx, 0 otherwise. |
| 418 | * out to be nice and simple | ||
| 419 | */ | 417 | */ |
| 420 | 418 | static int piix_is_ichx(struct pci_dev *dev) | |
| 421 | static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) | ||
| 422 | { | 419 | { |
| 423 | switch(dev->device) { | 420 | switch (dev->device) { |
| 424 | case PCI_DEVICE_ID_INTEL_82801EB_1: | 421 | case PCI_DEVICE_ID_INTEL_82801EB_1: |
| 425 | case PCI_DEVICE_ID_INTEL_82801AA_1: | 422 | case PCI_DEVICE_ID_INTEL_82801AA_1: |
| 426 | case PCI_DEVICE_ID_INTEL_82801AB_1: | 423 | case PCI_DEVICE_ID_INTEL_82801AB_1: |
| @@ -438,19 +435,51 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char | |||
| 438 | case PCI_DEVICE_ID_INTEL_ICH7_21: | 435 | case PCI_DEVICE_ID_INTEL_ICH7_21: |
| 439 | case PCI_DEVICE_ID_INTEL_ESB2_18: | 436 | case PCI_DEVICE_ID_INTEL_ESB2_18: |
| 440 | case PCI_DEVICE_ID_INTEL_ICH8_6: | 437 | case PCI_DEVICE_ID_INTEL_ICH8_6: |
| 441 | { | 438 | return 1; |
| 442 | unsigned int extra = 0; | ||
| 443 | pci_read_config_dword(dev, 0x54, &extra); | ||
| 444 | pci_write_config_dword(dev, 0x54, extra|0x400); | ||
| 445 | } | ||
| 446 | default: | ||
| 447 | break; | ||
| 448 | } | 439 | } |
| 449 | 440 | ||
| 450 | return 0; | 441 | return 0; |
| 451 | } | 442 | } |
| 452 | 443 | ||
| 453 | /** | 444 | /** |
| 445 | * init_chipset_piix - set up the PIIX chipset | ||
| 446 | * @dev: PCI device to set up | ||
| 447 | * @name: Name of the device | ||
| 448 | * | ||
| 449 | * Initialize the PCI device as required. For the PIIX this turns | ||
| 450 | * out to be nice and simple | ||
| 451 | */ | ||
| 452 | |||
| 453 | static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name) | ||
| 454 | { | ||
| 455 | if (piix_is_ichx(dev)) { | ||
| 456 | unsigned int extra = 0; | ||
| 457 | pci_read_config_dword(dev, 0x54, &extra); | ||
| 458 | pci_write_config_dword(dev, 0x54, extra|0x400); | ||
| 459 | } | ||
| 460 | |||
| 461 | return 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | /** | ||
| 465 | * piix_dma_clear_irq - clear BMDMA status | ||
| 466 | * @drive: IDE drive to clear | ||
| 467 | * | ||
| 468 | * Called from ide_intr() for PIO interrupts | ||
| 469 | * to clear BMDMA status as needed by ICHx | ||
| 470 | */ | ||
| 471 | static void piix_dma_clear_irq(ide_drive_t *drive) | ||
| 472 | { | ||
| 473 | ide_hwif_t *hwif = HWIF(drive); | ||
| 474 | u8 dma_stat; | ||
| 475 | |||
| 476 | /* clear the INTR & ERROR bits */ | ||
| 477 | dma_stat = hwif->INB(hwif->dma_status); | ||
| 478 | /* Should we force the bit as well ? */ | ||
| 479 | hwif->OUTB(dma_stat, hwif->dma_status); | ||
| 480 | } | ||
| 481 | |||
| 482 | /** | ||
| 454 | * init_hwif_piix - fill in the hwif for the PIIX | 483 | * init_hwif_piix - fill in the hwif for the PIIX |
| 455 | * @hwif: IDE interface | 484 | * @hwif: IDE interface |
| 456 | * | 485 | * |
| @@ -486,6 +515,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif) | |||
| 486 | if (!hwif->dma_base) | 515 | if (!hwif->dma_base) |
| 487 | return; | 516 | return; |
| 488 | 517 | ||
| 518 | /* ICHx need to clear the bmdma status for all interrupts */ | ||
| 519 | if (piix_is_ichx(hwif->pci_dev)) | ||
| 520 | hwif->ide_dma_clear_irq = &piix_dma_clear_irq; | ||
| 521 | |||
| 489 | hwif->atapi_dma = 1; | 522 | hwif->atapi_dma = 1; |
| 490 | hwif->ultra_mask = 0x3f; | 523 | hwif->ultra_mask = 0x3f; |
| 491 | hwif->mwdma_mask = 0x06; | 524 | hwif->mwdma_mask = 0x06; |
