]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ide: clear bmdma status in ide_intr() for ICHx controllers (revised #4)
authorAlbert Lee <albertcc@tw.ibm.com>
Sun, 22 Jul 2007 16:05:44 +0000 (18:05 +0200)
committerAdrian Bunk <bunk@stusta.de>
Sun, 22 Jul 2007 16:05:44 +0000 (18:05 +0200)
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>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
drivers/ide/ide-cd.c
drivers/ide/ide-io.c
drivers/ide/ide.c
drivers/ide/pci/piix.c
include/linux/ide.h

index 3325660f7248561b3b490d971581dc0b8033e1cd..72c4dd896bec138c9e1ee7008feef4b9eb47011d 100644 (file)
@@ -859,6 +859,10 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
                HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
  
        if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) {
+               /* waiting for CDB interrupt, not DMA yet. */
+               if (info->dma)
+                       drive->waiting_for_dma = 0;
+
                /* packet command */
                ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry);
                return ide_started;
@@ -901,6 +905,10 @@ static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
                /* Check for errors. */
                if (cdrom_decode_status(drive, DRQ_STAT, NULL))
                        return ide_stopped;
+
+               /* Ok, next interrupt will be DMA interrupt. */
+               if (info->dma)
+                       drive->waiting_for_dma = 1;
        } else {
                /* Otherwise, we must wait for DRQ to get set. */
                if (ide_wait_stat(&startstop, drive, DRQ_STAT,
index 574855456d45d8c539697237e8f2624ea598b689..bbad32f3ca2c5165f02f561676f9c237f578ab6b 100644 (file)
@@ -1561,6 +1561,17 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs)
        del_timer(&hwgroup->timer);
        spin_unlock(&ide_lock);
 
+       /* Some controllers might set DMA INTR no matter DMA or PIO;
+        * bmdma status might need to be cleared even for
+        * PIO interrupts to prevent spurious/lost irq.
+        */
+       if (hwif->ide_dma_clear_irq && !(drive->waiting_for_dma))
+               /* ide_dma_end() needs bmdma status for error checking.
+                * So, skip clearing bmdma status here and leave it
+                * to ide_dma_end() if this is dma interrupt.
+                */
+               hwif->ide_dma_clear_irq(drive);
+
        if (drive->unmask)
                local_irq_enable();
        /* service this interrupt, may set handler for next interrupt */
index b2cc43702f65ab5738e533c4152ba3aa9f90f3e7..1485ba8e05c962e1c87d1e34b0b28bd719a14fda 100644 (file)
@@ -505,6 +505,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
        hwif->ide_dma_on                = tmp_hwif->ide_dma_on;
        hwif->ide_dma_off_quietly       = tmp_hwif->ide_dma_off_quietly;
        hwif->ide_dma_test_irq          = tmp_hwif->ide_dma_test_irq;
+       hwif->ide_dma_clear_irq         = tmp_hwif->ide_dma_clear_irq;
        hwif->ide_dma_host_on           = tmp_hwif->ide_dma_host_on;
        hwif->ide_dma_host_off          = tmp_hwif->ide_dma_host_off;
        hwif->ide_dma_lostirq           = tmp_hwif->ide_dma_lostirq;
index e9b83e1a30287adf49475ab729b95c7b3d4c380c..d41538b8a18aefb7fd2627dcb3ceff89982c9809 100644 (file)
@@ -423,17 +423,14 @@ fast_ata_pio:
 }
 
 /**
- *     init_chipset_piix       -       set up the PIIX chipset
- *     @dev: PCI device to set up
- *     @name: Name of the device
+ *     piix_is_ichx    -       check if ICHx
+ *     @dev: PCI device to check
  *
- *     Initialize the PCI device as required. For the PIIX this turns
- *     out to be nice and simple
+ *     returns 1 if ICHx, 0 otherwise.
  */
-static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+static int piix_is_ichx(struct pci_dev *dev)
 {
-        switch(dev->device) {
+        switch (dev->device) {
                case PCI_DEVICE_ID_INTEL_82801EB_1:
                case PCI_DEVICE_ID_INTEL_82801AA_1:
                case PCI_DEVICE_ID_INTEL_82801AB_1:
@@ -451,18 +448,50 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char
                case PCI_DEVICE_ID_INTEL_ICH7_21:
                case PCI_DEVICE_ID_INTEL_ESB2_18:
                case PCI_DEVICE_ID_INTEL_ICH8_6:
-               {
-                       unsigned int extra = 0;
-                       pci_read_config_dword(dev, 0x54, &extra);
-                       pci_write_config_dword(dev, 0x54, extra|0x400);
-               }
-               default:
-                       break;
+                       return 1;
        }
 
        return 0;
 }
 
+/**
+ *     init_chipset_piix       -       set up the PIIX chipset
+ *     @dev: PCI device to set up
+ *     @name: Name of the device
+ *
+ *     Initialize the PCI device as required. For the PIIX this turns
+ *     out to be nice and simple
+ */
+
+static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char *name)
+{
+       if (piix_is_ichx(dev)) {
+               unsigned int extra = 0;
+               pci_read_config_dword(dev, 0x54, &extra);
+               pci_write_config_dword(dev, 0x54, extra|0x400);
+       }
+
+       return 0;
+}
+
+/**
+ *     piix_dma_clear_irq      -       clear BMDMA status
+ *     @drive: IDE drive to clear
+ *
+ *     Called from ide_intr() for PIO interrupts
+ *     to clear BMDMA status as needed by ICHx
+ */
+static void piix_dma_clear_irq(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = HWIF(drive);
+       u8 dma_stat;
+
+       /* clear the INTR & ERROR bits */
+       dma_stat = hwif->INB(hwif->dma_status);
+       /* Should we force the bit as well ? */
+       hwif->OUTB(dma_stat, hwif->dma_status);
+}
+
 /**
  *     init_hwif_piix          -       fill in the hwif for the PIIX
  *     @hwif: IDE interface
@@ -495,6 +524,10 @@ static void __devinit init_hwif_piix(ide_hwif_t *hwif)
        if (!hwif->dma_base)
                return;
 
+       /* ICHx need to clear the bmdma status for all interrupts */
+       if (piix_is_ichx(hwif->pci_dev))
+               hwif->ide_dma_clear_irq = &piix_dma_clear_irq;
+
        hwif->atapi_dma = 1;
        hwif->ultra_mask = 0x3f;
        hwif->mwdma_mask = 0x06;
index a7fc4cc79b235f5ffefae57b99c2668d1ed3397a..24819bac72501f7c8501052f53671fe3ec786226 100644 (file)
@@ -726,6 +726,7 @@ typedef struct hwif_s {
        int (*ide_dma_on)(ide_drive_t *drive);
        int (*ide_dma_off_quietly)(ide_drive_t *drive);
        int (*ide_dma_test_irq)(ide_drive_t *drive);
+       void (*ide_dma_clear_irq)(ide_drive_t *drive);
        int (*ide_dma_host_on)(ide_drive_t *drive);
        int (*ide_dma_host_off)(ide_drive_t *drive);
        int (*ide_dma_lostirq)(ide_drive_t *drive);