aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-05-05 16:03:50 -0400
committerBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2007-05-05 16:03:50 -0400
commit0e9b4e535fec7e2a189952670937adfbe2826b63 (patch)
tree2070bf76a4e1d1e5b492b7b061f57564f803b45d /drivers
parent247b03f8dc4c01659030889f7fb4574013974ac6 (diff)
it821x: PIO mode setup fixes
* limit max PIO mode to PIO4, this driver doesn't support PIO5 and attempt to setup PIO5 by it821x_tuneproc() could result in incorrect PIO timings + incorrect base clock being set for controller in the passthrough mode * move code limiting max PIO according to the pair device capabilities from config_it821x_chipset_for_pio() to it821x_tuneproc() so the check is also applied for mode change requests coming through ->tuneproc and ->speedproc interfaces * set device speed in it821x_tuneproc() * in it821x_tune_chipset() call it821x_tuneproc() also if the controller is in the smart mode (so the check for pair device max PIO is done) * rename it821x_tuneproc() to it821x_tune_pio(), then add it821x_tuneproc() wrapper which does the max PIO mode check; it worked by the pure luck previously, pio[4] and pio_want[4] arrays were used with index == 255 so random PIO timings and base clock were set for the controller in the passthrough mode, thankfully PIO timings and base clock were corrected later by config_it821x_chipset_for_pio() call (but it was not called for PIO-only devices during resume and for user requested PIO autotuning) * remove config_it821x_chipset_for_pio() call from config_chipset_for_dma() as the driver sets ->autotune to 1 and ->tuneproc does the proper job now * convert the last user of config_it821x_chipset_for_pio() to use it821x_tuneproc(drive, 255) and remove no longer needed function While at it: * fix few comments * bump driver version Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ide/pci/it821x.c126
1 files changed, 58 insertions, 68 deletions
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index a132767f7d90..4e1254813ee0 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -1,8 +1,9 @@
1 1
2/* 2/*
3 * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004 3 * linux/drivers/ide/pci/it821x.c Version 0.10 Mar 10 2007
4 * 4 *
5 * Copyright (C) 2004 Red Hat <alan@redhat.com> 5 * Copyright (C) 2004 Red Hat <alan@redhat.com>
6 * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
6 * 7 *
7 * May be copied or modified under the terms of the GNU General Public License 8 * May be copied or modified under the terms of the GNU General Public License
8 * Based in part on the ITE vendor provided SCSI driver. 9 * Based in part on the ITE vendor provided SCSI driver.
@@ -104,6 +105,7 @@ static int it8212_noraid;
104/** 105/**
105 * it821x_program - program the PIO/MWDMA registers 106 * it821x_program - program the PIO/MWDMA registers
106 * @drive: drive to tune 107 * @drive: drive to tune
108 * @timing: timing info
107 * 109 *
108 * Program the PIO/MWDMA timing for this channel according to the 110 * Program the PIO/MWDMA timing for this channel according to the
109 * current clock. 111 * current clock.
@@ -127,6 +129,7 @@ static void it821x_program(ide_drive_t *drive, u16 timing)
127/** 129/**
128 * it821x_program_udma - program the UDMA registers 130 * it821x_program_udma - program the UDMA registers
129 * @drive: drive to tune 131 * @drive: drive to tune
132 * @timing: timing info
130 * 133 *
131 * Program the UDMA timing for this drive according to the 134 * Program the UDMA timing for this drive according to the
132 * current clock. 135 * current clock.
@@ -153,10 +156,9 @@ static void it821x_program_udma(ide_drive_t *drive, u16 timing)
153 } 156 }
154} 157}
155 158
156
157/** 159/**
158 * it821x_clock_strategy 160 * it821x_clock_strategy
159 * @hwif: hardware interface 161 * @drive: drive to set up
160 * 162 *
161 * Select between the 50 and 66Mhz base clocks to get the best 163 * Select between the 50 and 66Mhz base clocks to get the best
162 * results for this interface. 164 * results for this interface.
@@ -182,8 +184,11 @@ static void it821x_clock_strategy(ide_drive_t *drive)
182 altclock = itdev->want[0][1]; 184 altclock = itdev->want[0][1];
183 } 185 }
184 186
185 /* Master doesn't care does the slave ? */ 187 /*
186 if(clock == ATA_ANY) 188 * if both clocks can be used for the mode with the higher priority
189 * use the clock needed by the mode with the lower priority
190 */
191 if (clock == ATA_ANY)
187 clock = altclock; 192 clock = altclock;
188 193
189 /* Nobody cares - keep the same clock */ 194 /* Nobody cares - keep the same clock */
@@ -240,37 +245,56 @@ static u8 it821x_ratemask (ide_drive_t *drive)
240} 245}
241 246
242/** 247/**
243 * it821x_tuneproc - tune a drive 248 * it821x_tunepio - tune a drive
244 * @drive: drive to tune 249 * @drive: drive to tune
245 * @mode_wanted: the target operating mode 250 * @pio: the desired PIO mode
246 *
247 * Load the timing settings for this device mode into the
248 * controller. By the time we are called the mode has been
249 * modified as neccessary to handle the absence of seperate
250 * master/slave timers for MWDMA/PIO.
251 * 251 *
252 * This code is only used in pass through mode. 252 * Try to tune the drive/host to the desired PIO mode taking into
253 * the consideration the maximum PIO mode supported by the other
254 * device on the cable.
253 */ 255 */
254 256
255static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted) 257static int it821x_tunepio(ide_drive_t *drive, u8 set_pio)
256{ 258{
257 ide_hwif_t *hwif = drive->hwif; 259 ide_hwif_t *hwif = drive->hwif;
258 struct it821x_dev *itdev = ide_get_hwifdata(hwif); 260 struct it821x_dev *itdev = ide_get_hwifdata(hwif);
259 int unit = drive->select.b.unit; 261 int unit = drive->select.b.unit;
262 ide_drive_t *pair = &hwif->drives[1 - unit];
260 263
261 /* Spec says 89 ref driver uses 88 */ 264 /* Spec says 89 ref driver uses 88 */
262 static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; 265 static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
263 static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; 266 static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
264 267
265 if(itdev->smart) 268 /*
266 return; 269 * Compute the best PIO mode we can for a given device. We must
270 * pick a speed that does not cause problems with the other device
271 * on the cable.
272 */
273 if (pair) {
274 u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
275 /* trim PIO to the slowest of the master/slave */
276 if (pair_pio < set_pio)
277 set_pio = pair_pio;
278 }
279
280 if (itdev->smart)
281 goto set_drive_speed;
267 282
268 /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */ 283 /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
269 itdev->want[unit][1] = pio_want[mode_wanted]; 284 itdev->want[unit][1] = pio_want[set_pio];
270 itdev->want[unit][0] = 1; /* PIO is lowest priority */ 285 itdev->want[unit][0] = 1; /* PIO is lowest priority */
271 itdev->pio[unit] = pio[mode_wanted]; 286 itdev->pio[unit] = pio[set_pio];
272 it821x_clock_strategy(drive); 287 it821x_clock_strategy(drive);
273 it821x_program(drive, itdev->pio[unit]); 288 it821x_program(drive, itdev->pio[unit]);
289
290set_drive_speed:
291 return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
292}
293
294static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
295{
296 pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
297 (void)it821x_tunepio(drive, pio);
274} 298}
275 299
276/** 300/**
@@ -354,40 +378,6 @@ static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
354} 378}
355 379
356/** 380/**
357 * config_it821x_chipset_for_pio - set drive timings
358 * @drive: drive to tune
359 * @speed we want
360 *
361 * Compute the best pio mode we can for a given device. We must
362 * pick a speed that does not cause problems with the other device
363 * on the cable.
364 */
365
366static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
367{
368 u8 unit = drive->select.b.unit;
369 ide_hwif_t *hwif = drive->hwif;
370 ide_drive_t *pair = &hwif->drives[1-unit];
371 u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
372 u8 pair_pio;
373
374 /* We have to deal with this mess in pairs */
375 if(pair != NULL) {
376 pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
377 /* Trim PIO to the slowest of the master/slave */
378 if(pair_pio < set_pio)
379 set_pio = pair_pio;
380 }
381 it821x_tuneproc(drive, set_pio);
382 speed = XFER_PIO_0 + set_pio;
383 /* XXX - We trim to the lowest of the pair so the other drive
384 will always be fine at this point until we do hotplug passthru */
385
386 if (set_speed)
387 (void) ide_config_drive_speed(drive, speed);
388}
389
390/**
391 * it821x_dma_read - DMA hook 381 * it821x_dma_read - DMA hook
392 * @drive: drive for DMA 382 * @drive: drive for DMA
393 * 383 *
@@ -450,15 +440,17 @@ static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
450 struct it821x_dev *itdev = ide_get_hwifdata(hwif); 440 struct it821x_dev *itdev = ide_get_hwifdata(hwif);
451 u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed); 441 u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed);
452 442
453 if(!itdev->smart) { 443 switch (speed) {
454 switch(speed) { 444 case XFER_PIO_4:
455 case XFER_PIO_4: 445 case XFER_PIO_3:
456 case XFER_PIO_3: 446 case XFER_PIO_2:
457 case XFER_PIO_2: 447 case XFER_PIO_1:
458 case XFER_PIO_1: 448 case XFER_PIO_0:
459 case XFER_PIO_0: 449 return it821x_tunepio(drive, speed - XFER_PIO_0);
460 it821x_tuneproc(drive, (speed - XFER_PIO_0)); 450 }
461 break; 451
452 if (itdev->smart == 0) {
453 switch (speed) {
462 /* MWDMA tuning is really hard because our MWDMA and PIO 454 /* MWDMA tuning is really hard because our MWDMA and PIO
463 timings are kept in the same place. We can switch in the 455 timings are kept in the same place. We can switch in the
464 host dma on/off callbacks */ 456 host dma on/off callbacks */
@@ -498,14 +490,12 @@ static int config_chipset_for_dma (ide_drive_t *drive)
498{ 490{
499 u8 speed = ide_dma_speed(drive, it821x_ratemask(drive)); 491 u8 speed = ide_dma_speed(drive, it821x_ratemask(drive));
500 492
501 if (speed) { 493 if (speed == 0)
502 config_it821x_chipset_for_pio(drive, 0); 494 return 0;
503 it821x_tune_chipset(drive, speed);
504 495
505 return ide_dma_enable(drive); 496 it821x_tune_chipset(drive, speed);
506 }
507 497
508 return 0; 498 return ide_dma_enable(drive);
509} 499}
510 500
511/** 501/**
@@ -523,7 +513,7 @@ static int it821x_config_drive_for_dma (ide_drive_t *drive)
523 if (ide_use_dma(drive) && config_chipset_for_dma(drive)) 513 if (ide_use_dma(drive) && config_chipset_for_dma(drive))
524 return 0; 514 return 0;
525 515
526 config_it821x_chipset_for_pio(drive, 1); 516 it821x_tuneproc(drive, 255);
527 517
528 return -1; 518 return -1;
529} 519}