Merge branch 'juju' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux13...
[powerpc.git] / drivers / ide / pci / it821x.c
index 3cb0442..442f658 100644 (file)
@@ -1,8 +1,9 @@
 
 /*
- * linux/drivers/ide/pci/it821x.c              Version 0.09    December 2004
+ * linux/drivers/ide/pci/it821x.c              Version 0.10    Mar 10 2007
  *
  * Copyright (C) 2004          Red Hat <alan@redhat.com>
+ * Copyright (C) 2007          Bartlomiej Zolnierkiewicz
  *
  *  May be copied or modified under the terms of the GNU General Public License
  *  Based in part on the ITE vendor provided SCSI driver.
@@ -104,6 +105,7 @@ static int it8212_noraid;
 /**
  *     it821x_program  -       program the PIO/MWDMA registers
  *     @drive: drive to tune
+ *     @timing: timing info
  *
  *     Program the PIO/MWDMA timing for this channel according to the
  *     current clock.
@@ -127,6 +129,7 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
 /**
  *     it821x_program_udma     -       program the UDMA registers
  *     @drive: drive to tune
+ *     @timing: timing info
  *
  *     Program the UDMA timing for this drive according to the
  *     current clock.
@@ -153,10 +156,9 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
        }
 }
 
-
 /**
  *     it821x_clock_strategy
- *     @hwif: hardware interface
+ *     @drive: drive to set up
  *
  *     Select between the 50 and 66Mhz base clocks to get the best
  *     results for this interface.
@@ -182,8 +184,11 @@ static void it821x_clock_strategy(ide_drive_t *drive)
                altclock = itdev->want[0][1];
        }
 
-       /* Master doesn't care does the slave ? */
-       if(clock == ATA_ANY)
+       /*
+        * if both clocks can be used for the mode with the higher priority
+        * use the clock needed by the mode with the lower priority
+        */
+       if (clock == ATA_ANY)
                clock = altclock;
 
        /* Nobody cares - keep the same clock */
@@ -224,53 +229,56 @@ static void it821x_clock_strategy(ide_drive_t *drive)
 }
 
 /**
- *     it821x_ratemask -       Compute available modes
- *     @drive: IDE drive
- *
- *     Compute the available speeds for the devices on the interface. This
- *     is all modes to ATA133 clipped by drive cable setup.
- */
-
-static u8 it821x_ratemask (ide_drive_t *drive)
-{
-       u8 mode = 4;
-       if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
-       return mode;
-}
-
-/**
- *     it821x_tuneproc -       tune a drive
+ *     it821x_tunepio  -       tune a drive
  *     @drive: drive to tune
- *     @mode_wanted: the target operating mode
- *
- *     Load the timing settings for this device mode into the
- *     controller. By the time we are called the mode has been
- *     modified as neccessary to handle the absence of seperate
- *     master/slave timers for MWDMA/PIO.
+ *     @pio: the desired PIO mode
  *
- *     This code is only used in pass through mode.
+ *     Try to tune the drive/host to the desired PIO mode taking into
+ *     the consideration the maximum PIO mode supported by the other
+ *     device on the cable.
  */
 
-static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted)
+static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
 {
        ide_hwif_t *hwif        = drive->hwif;
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
        int unit = drive->select.b.unit;
+       ide_drive_t *pair = &hwif->drives[1 - unit];
 
        /* Spec says 89 ref driver uses 88 */
        static u16 pio[]        = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
        static u8 pio_want[]    = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
 
-       if(itdev->smart)
-               return;
+       /*
+        * Compute the best PIO mode we can for a given device. We must
+        * pick a speed that does not cause problems with the other device
+        * on the cable.
+        */
+       if (pair) {
+               u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
+               /* trim PIO to the slowest of the master/slave */
+               if (pair_pio < set_pio)
+                       set_pio = pair_pio;
+       }
+
+       if (itdev->smart)
+               goto set_drive_speed;
 
        /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
-       itdev->want[unit][1] = pio_want[mode_wanted];
+       itdev->want[unit][1] = pio_want[set_pio];
        itdev->want[unit][0] = 1;       /* PIO is lowest priority */
-       itdev->pio[unit] = pio[mode_wanted];
+       itdev->pio[unit] = pio[set_pio];
        it821x_clock_strategy(drive);
        it821x_program(drive, itdev->pio[unit]);
+
+set_drive_speed:
+       return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
+}
+
+static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
+{
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       (void)it821x_tunepio(drive, pio);
 }
 
 /**
@@ -353,40 +361,6 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
 
 }
 
-/**
- *     config_it821x_chipset_for_pio   -       set drive timings
- *     @drive: drive to tune
- *     @speed we want
- *
- *     Compute the best pio mode we can for a given device. We must
- *     pick a speed that does not cause problems with the other device
- *     on the cable.
- */
-
-static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-       u8 unit = drive->select.b.unit;
-       ide_hwif_t *hwif = drive->hwif;
-       ide_drive_t *pair = &hwif->drives[1-unit];
-       u8 speed = 0, set_pio   = ide_get_best_pio_mode(drive, 255, 5, NULL);
-       u8 pair_pio;
-
-       /* We have to deal with this mess in pairs */
-       if(pair != NULL) {
-               pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
-               /* Trim PIO to the slowest of the master/slave */
-               if(pair_pio < set_pio)
-                       set_pio = pair_pio;
-       }
-       it821x_tuneproc(drive, set_pio);
-       speed = XFER_PIO_0 + set_pio;
-       /* XXX - We trim to the lowest of the pair so the other drive
-          will always be fine at this point until we do hotplug passthru */
-
-       if (set_speed)
-               (void) ide_config_drive_speed(drive, speed);
-}
-
 /**
  *     it821x_dma_read -       DMA hook
  *     @drive: drive for DMA
@@ -448,17 +422,19 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
 
        ide_hwif_t *hwif        = drive->hwif;
        struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-       u8 speed                = ide_rate_filter(it821x_ratemask(drive), xferspeed);
+       u8 speed                = ide_rate_filter(drive, xferspeed);
+
+       switch (speed) {
+       case XFER_PIO_4:
+       case XFER_PIO_3:
+       case XFER_PIO_2:
+       case XFER_PIO_1:
+       case XFER_PIO_0:
+               return it821x_tunepio(drive, speed - XFER_PIO_0);
+       }
 
-       if(!itdev->smart) {
-               switch(speed) {
-                       case XFER_PIO_4:
-                       case XFER_PIO_3:
-                       case XFER_PIO_2:
-                       case XFER_PIO_1:
-                       case XFER_PIO_0:
-                               it821x_tuneproc(drive, (speed - XFER_PIO_0));
-                               break;
+       if (itdev->smart == 0) {
+               switch (speed) {
                        /* MWDMA tuning is really hard because our MWDMA and PIO
                           timings are kept in the same place. We can switch in the
                           host dma on/off callbacks */
@@ -496,10 +472,13 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
 
 static int config_chipset_for_dma (ide_drive_t *drive)
 {
-       u8 speed        = ide_dma_speed(drive, it821x_ratemask(drive));
+       u8 speed = ide_max_dma_mode(drive);
+
+       if (speed == 0)
+               return 0;
 
-       config_it821x_chipset_for_pio(drive, !speed);
        it821x_tune_chipset(drive, speed);
+
        return ide_dma_enable(drive);
 }
 
@@ -515,14 +494,12 @@ static int config_chipset_for_dma (ide_drive_t *drive)
 
 static int it821x_config_drive_for_dma (ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = drive->hwif;
+       if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+               return 0;
 
-       if (ide_use_dma(drive)) {
-               if (config_chipset_for_dma(drive))
-                       return hwif->ide_dma_on(drive);
-       }
-       config_it821x_chipset_for_pio(drive, 1);
-       return hwif->ide_dma_off_quietly(drive);
+       it821x_tuneproc(drive, 255);
+
+       return -1;
 }
 
 /**
@@ -603,11 +580,11 @@ static void __devinit it821x_fixups(ide_hwif_t *hwif)
                                printk(".\n");
                        /* Now the core code will have wrongly decided no DMA
                           so we need to fix this */
-                       hwif->ide_dma_off_quietly(drive);
+                       hwif->dma_off_quietly(drive);
 #ifdef CONFIG_IDEDMA_ONLYDISK
                        if (drive->media == ide_disk)
 #endif
-                               hwif->ide_dma_check(drive);
+                               ide_set_dma(drive);
                } else {
                        /* Non RAID volume. Fixups to stop the core code
                           doing unsupported things */