diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-05-05 16:03:50 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-05-05 16:03:50 -0400 |
commit | 0e9b4e535fec7e2a189952670937adfbe2826b63 (patch) | |
tree | 2070bf76a4e1d1e5b492b7b061f57564f803b45d /drivers | |
parent | 247b03f8dc4c01659030889f7fb4574013974ac6 (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.c | 126 |
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 | ||
255 | static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted) | 257 | static 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 | |||
290 | set_drive_speed: | ||
291 | return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio); | ||
292 | } | ||
293 | |||
294 | static 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 | |||
366 | static 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 | } |