diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-10-11 17:53:59 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-10-11 17:53:59 -0400 |
commit | 7670df73fba373d19471a2ebedb3302ea0607be0 (patch) | |
tree | a47b896a9d9a652ca71cc33709f0f73253ea5f9c | |
parent | a8028fcb485522c0d7de9c5423812de9224b37c9 (diff) |
ide: mode limiting fixes for user requested speed changes
* Add an extra argument to ide_max_dma_mode() for passing requested transfer
mode. Use it as an upper limit when finding the best DMA for device/host.
* Rename ide_max_dma_mode() to ide_find_dma_mode() and at the same time add
ide_max_dma_mode() wrapper which passes XFER_UDMA_6 as a requested mode to
ide_find_dma_mode(). Also add inline ide_find_dma_mode() version for
CONFIG_BLK_DEV_IDEDMA=n case.
* Pass requested transfer mode from ide_find_dma_mode() to ide_get_mode_mask()
to avoid false warning from eighty_ninty_three().
* Use ide_find_dma_mode() to limit the user requested transfer mode in
ide_rate_filter(). Also limit the requested mode by host max PIO mode.
Above changes make ide_rate_filter() to:
* Clip desired transfer mode down if it is invalid (values 0x0F, 0x13-0x19
and 0x25-0x39, values > 0x46 were already clipped down, same for values
0x25-0x39 but iff UDMA was not supported by the host).
* Clip desired transfer mode down if it is currently unsupported by IDE core
(PIO6 and MWDMA3-4, the latter were already clipped down but iff UDMA was
not supported by the host).
* Clip desired transfer mode down according to the host capabilities
(UDMA modes were already clipped down but MWDMA/SWDMA/PIO weren't,
also ->atapi_dma flag was not respected).
* Clip desired transfer mode down according to the device capabilities
(except PIO modes for now which require mode work) - shouldn't be a
problem since ide_set_xfer_rate() is called _after_ device has accepted
given transfer mode.
and also result in a number of host driver specific bugfixes:
* icside
- clip unsupported PIO5 mode down
- fix unsupported/invalid modes being set in drive->current_speed
* ide-cris
- clip unsupported PIO5 and SWDMA0-2 modes down
- clip DMA modes down for ATAPI devices
- fix BUG() on unsupported/invalid modes
* au1xxx-ide
- clip unsupported PIO5, SWDMA0-2 and MWDMA0-2
(if BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA=n) modes down
* aec62xx
- clip unsupported PIO5 and SWDMA0-2 modes down
- clip DMA modes down for ATAPI devices
- fix 0x00 being programmed as PIO timing for unsupported/invalid modes
- fix unsupported/invalid modes being set on the device
* alim15x3
- clip DMA modes down for ATAPI devices (chipset revision == 0x20 only)
- fix theoretical OOPS for 0x0F mode
- fix unsupported/invalid modes being set on the device
* amd74xx
- clip unsupported SWDMA0-2 (on COBRA_7401 revs <= 7) modes down
- fix random PIO timings being set for unsupported/invalid modes
- fix unsupported/invalid modes being set on the device
* atiixp
- clip unsupported PIO5 and SWDMA0-2 modes down
- fix cached MWDMA mode being cleared for unsupported/invalid modes
- fix PIO{0,2} timings being programmed for unsupported/invalid modes
- fix theoretical OOPS for PIO5-6 and 0x0F modes
- fix unsupported/invalid modes being set on the device
* cmd64x
- clip unsupported SWDMA0-2 modes down
* cs5530
- clip unsupported PIO5 and SWDMA0-2 modes down
- fix unsupported/invalid modes being set on the device
- fix BUG() on unsupported/invalid modes
(which happened if the device accepted the setting)
* cs5535
- clip unsupported PIO5 and SWDMA0-2 modes down
- fix unsupported/invalid modes being set on the device
- fix theoretical OOPS for PIO5-6 and 0x0F modes
* hpt34x
- clip DMA modes down for ATAPI devices
- fix invalid timings being programmed for unsupported/invalid modes
- fix unsupported/invalid modes being set on the device
* hpt366
- clip unsupported PIO5 and SWDMA0-2 modes down
- fix PIO0 timings being programmed for unsupported/invalid modes
- fix DMA timings being cleared for MWDMA3-4 and 0x25-0x39 modes
- fix unsupported/invalid modes being set on the device
* it8213
- clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down
* it821x
- clip unsupported PIO5 and SWDMA0-2 modes down
- clip DMA modes down for ATAPI devices
(chipset in smart mode and revision 0x10 in pass-through mode)
* jmicron
- clip unsupported SWDMA0-2 modes down
- fix unsupported/invalid modes being set on the device
* pdc202xx_new
- clip unsupported PIO5 and SWDMA0-2 modes down
- fix unsupported/invalid modes being set on the device
* pdc202xx_old
- clip unsupported PIO5 mode down
- fix incorrect timings being set for unsupported/invalid modes
- fix unsupported/invalid modes being set on the device
* piix
- clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down
* sc1200
- clip unsupported PIO5 and SWDMA0-2 modes down
- fix unsupported/invalid modes being set on the device
- fix BUG() on unsupported/invalid modes
(which happened if the device accepted the setting)
* scc_pata
- clip unsupported PIO5, SWDMA0-2 and MWDMA0-2 modes down
* serverworks
- clip unsupported PIO5 and SWDMA0-2 modes down
- fix DMA/UDMA timings/settings being cleared for unsupported/invalid modes
- fix unsupported/invalid modes being set on the device
* siimage
- clip unsupported PIO5 and SWDMA0-2 modes down
- clip DMA modes down for ATAPI devices (SATA chipsets)
* sis5513
- clip unsupported PIO5 mode down
- fix BUG() on unsupported/invalid modes
* sl82c105
- clip unsupported SWDMA0-2 modes down
* slc90e66
- clip unsupported PIO5, SWDMA0-1 and MWDMA0 modes down
* tc86c001
- clip unsupported PIO5 and SWDMA0-2 modes down
- fix PIO0 timings being programmed for PIO5/0x0F/SWDMA0-2/0x13-0x19 modes
- fix invalid 0x00 DMA timing being programmed for MWDMA3-4/0x25-0x39 modes
- fix unsupported/invalid modes being set on the device
* triflex
- clip unsupported PIO5 mode down
* via82cxxx
- fix random PIO timings being set for unsupported/invalid modes
- fix unsupported/invalid modes being set on the device
* pmac
- clip unsupported PIO5 and SWDMA0-2 modes down
* cmd640/ht6560b
- clip DMA modes down (if CONFIG_BLK_DEV_IDEDMA=y)
- fix PIO5 being clipped to PIO4 (if CONFIG_BLK_DEV_IDEDMA=n)
* opti621
- clip DMA modes down (if CONFIG_BLK_DEV_IDEDMA=y)
- clip unsupported PIO4 to PIO3 (if CONFIG_BLK_DEV_IDEDMA=n)
While at it:
* Use ide_rate_filter() in cs5520.c::cs5520_tune_chipset().
* Remove no longer needed checks from hpt366.c::hpt3{6,7}x_tune_chipset().
Acked-by: Sergei Shtylyov <sshtylyov@ru.mvista.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
-rw-r--r-- | drivers/ide/ide-dma.c | 32 | ||||
-rw-r--r-- | drivers/ide/ide-lib.c | 29 | ||||
-rw-r--r-- | drivers/ide/pci/cs5520.c | 2 | ||||
-rw-r--r-- | drivers/ide/pci/hpt366.c | 8 | ||||
-rw-r--r-- | include/linux/ide.h | 10 |
5 files changed, 39 insertions, 42 deletions
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index f073ea35da00..6000c08f51ba 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c | |||
@@ -653,7 +653,7 @@ static const u8 xfer_mode_bases[] = { | |||
653 | XFER_SW_DMA_0, | 653 | XFER_SW_DMA_0, |
654 | }; | 654 | }; |
655 | 655 | ||
656 | static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) | 656 | static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode) |
657 | { | 657 | { |
658 | struct hd_driveid *id = drive->id; | 658 | struct hd_driveid *id = drive->id; |
659 | ide_hwif_t *hwif = drive->hwif; | 659 | ide_hwif_t *hwif = drive->hwif; |
@@ -670,8 +670,13 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) | |||
670 | mask = hwif->ultra_mask; | 670 | mask = hwif->ultra_mask; |
671 | mask &= id->dma_ultra; | 671 | mask &= id->dma_ultra; |
672 | 672 | ||
673 | if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) | 673 | /* |
674 | mask &= 0x07; | 674 | * avoid false cable warning from eighty_ninty_three() |
675 | */ | ||
676 | if (req_mode > XFER_UDMA_2) { | ||
677 | if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) | ||
678 | mask &= 0x07; | ||
679 | } | ||
675 | break; | 680 | break; |
676 | case XFER_MW_DMA_0: | 681 | case XFER_MW_DMA_0: |
677 | if ((id->field_valid & 2) == 0) | 682 | if ((id->field_valid & 2) == 0) |
@@ -709,15 +714,18 @@ static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base) | |||
709 | } | 714 | } |
710 | 715 | ||
711 | /** | 716 | /** |
712 | * ide_max_dma_mode - compute DMA speed | 717 | * ide_find_dma_mode - compute DMA speed |
713 | * @drive: IDE device | 718 | * @drive: IDE device |
719 | * @req_mode: requested mode | ||
720 | * | ||
721 | * Checks the drive/host capabilities and finds the speed to use for | ||
722 | * the DMA transfer. The speed is then limited by the requested mode. | ||
714 | * | 723 | * |
715 | * Checks the drive capabilities and returns the speed to use | 724 | * Returns 0 if the drive/host combination is incapable of DMA transfers |
716 | * for the DMA transfer. Returns 0 if the drive is incapable | 725 | * or if the requested mode is not a DMA mode. |
717 | * of DMA transfers. | ||
718 | */ | 726 | */ |
719 | 727 | ||
720 | u8 ide_max_dma_mode(ide_drive_t *drive) | 728 | u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode) |
721 | { | 729 | { |
722 | ide_hwif_t *hwif = drive->hwif; | 730 | ide_hwif_t *hwif = drive->hwif; |
723 | unsigned int mask; | 731 | unsigned int mask; |
@@ -728,7 +736,9 @@ u8 ide_max_dma_mode(ide_drive_t *drive) | |||
728 | return 0; | 736 | return 0; |
729 | 737 | ||
730 | for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) { | 738 | for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) { |
731 | mask = ide_get_mode_mask(drive, xfer_mode_bases[i]); | 739 | if (req_mode < xfer_mode_bases[i]) |
740 | continue; | ||
741 | mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode); | ||
732 | x = fls(mask) - 1; | 742 | x = fls(mask) - 1; |
733 | if (x >= 0) { | 743 | if (x >= 0) { |
734 | mode = xfer_mode_bases[i] + x; | 744 | mode = xfer_mode_bases[i] + x; |
@@ -738,10 +748,10 @@ u8 ide_max_dma_mode(ide_drive_t *drive) | |||
738 | 748 | ||
739 | printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode); | 749 | printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode); |
740 | 750 | ||
741 | return mode; | 751 | return min(mode, req_mode); |
742 | } | 752 | } |
743 | 753 | ||
744 | EXPORT_SYMBOL_GPL(ide_max_dma_mode); | 754 | EXPORT_SYMBOL_GPL(ide_find_dma_mode); |
745 | 755 | ||
746 | int ide_tune_dma(ide_drive_t *drive) | 756 | int ide_tune_dma(ide_drive_t *drive) |
747 | { | 757 | { |
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index 92a6c7bcf527..41a128f52112 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c | |||
@@ -76,37 +76,24 @@ EXPORT_SYMBOL(ide_xfer_verbose); | |||
76 | * Given the available transfer modes this function returns | 76 | * Given the available transfer modes this function returns |
77 | * the best available speed at or below the speed requested. | 77 | * the best available speed at or below the speed requested. |
78 | * | 78 | * |
79 | * FIXME: filter also PIO/SWDMA/MWDMA modes | 79 | * TODO: check device PIO capabilities |
80 | */ | 80 | */ |
81 | 81 | ||
82 | u8 ide_rate_filter(ide_drive_t *drive, u8 speed) | 82 | u8 ide_rate_filter(ide_drive_t *drive, u8 speed) |
83 | { | 83 | { |
84 | #ifdef CONFIG_BLK_DEV_IDEDMA | ||
85 | ide_hwif_t *hwif = drive->hwif; | 84 | ide_hwif_t *hwif = drive->hwif; |
86 | u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2; | 85 | u8 mode = ide_find_dma_mode(drive, speed); |
87 | |||
88 | if (hwif->udma_filter) | ||
89 | mask = hwif->udma_filter(drive); | ||
90 | |||
91 | /* | ||
92 | * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false | ||
93 | * cable warning from eighty_ninty_three(), moving ide_rate_filter() | ||
94 | * calls from ->speedproc to core code will make this hack go away | ||
95 | */ | ||
96 | if (speed > XFER_UDMA_2) { | ||
97 | if ((mask & 0x78) && (eighty_ninty_three(drive) == 0)) | ||
98 | mask &= 0x07; | ||
99 | } | ||
100 | 86 | ||
101 | if (mask) | 87 | if (mode == 0) { |
102 | mode = fls(mask) - 1 + XFER_UDMA_0; | 88 | if (hwif->pio_mask) |
89 | mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0; | ||
90 | else | ||
91 | mode = XFER_PIO_4; | ||
92 | } | ||
103 | 93 | ||
104 | // printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed); | 94 | // printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed); |
105 | 95 | ||
106 | return min(speed, mode); | 96 | return min(speed, mode); |
107 | #else /* !CONFIG_BLK_DEV_IDEDMA */ | ||
108 | return min(speed, (u8)XFER_PIO_4); | ||
109 | #endif /* CONFIG_BLK_DEV_IDEDMA */ | ||
110 | } | 97 | } |
111 | 98 | ||
112 | EXPORT_SYMBOL(ide_rate_filter); | 99 | EXPORT_SYMBOL(ide_rate_filter); |
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c index b89e81656875..507981042c82 100644 --- a/drivers/ide/pci/cs5520.c +++ b/drivers/ide/pci/cs5520.c | |||
@@ -70,7 +70,7 @@ static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed) | |||
70 | { | 70 | { |
71 | ide_hwif_t *hwif = HWIF(drive); | 71 | ide_hwif_t *hwif = HWIF(drive); |
72 | struct pci_dev *pdev = hwif->pci_dev; | 72 | struct pci_dev *pdev = hwif->pci_dev; |
73 | u8 speed = min((u8)XFER_PIO_4, xferspeed); | 73 | u8 speed = ide_rate_filter(drive, xferspeed); |
74 | int pio = speed; | 74 | int pio = speed; |
75 | u8 reg; | 75 | u8 reg; |
76 | int controller = drive->dn > 1 ? 1 : 0; | 76 | int controller = drive->dn > 1 ? 1 : 0; |
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c index 3d8d6b2ee41a..18c8ad091eb3 100644 --- a/drivers/ide/pci/hpt366.c +++ b/drivers/ide/pci/hpt366.c | |||
@@ -610,10 +610,6 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) | |||
610 | u32 old_itr = 0; | 610 | u32 old_itr = 0; |
611 | u32 itr_mask, new_itr; | 611 | u32 itr_mask, new_itr; |
612 | 612 | ||
613 | /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */ | ||
614 | if (drive->media != ide_disk) | ||
615 | speed = min_t(u8, speed, XFER_PIO_4); | ||
616 | |||
617 | itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 : | 613 | itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 : |
618 | (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff); | 614 | (speed < XFER_UDMA_0 ? 0xc0070000 : 0xc03800ff); |
619 | 615 | ||
@@ -642,10 +638,6 @@ static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed) | |||
642 | u32 old_itr = 0; | 638 | u32 old_itr = 0; |
643 | u32 itr_mask, new_itr; | 639 | u32 itr_mask, new_itr; |
644 | 640 | ||
645 | /* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */ | ||
646 | if (drive->media != ide_disk) | ||
647 | speed = min_t(u8, speed, XFER_PIO_4); | ||
648 | |||
649 | itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 : | 641 | itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 : |
650 | (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff); | 642 | (speed < XFER_UDMA_0 ? 0xc03c0000 : 0xc1c001ff); |
651 | 643 | ||
diff --git a/include/linux/ide.h b/include/linux/ide.h index 80ea946282d7..a3f9c216615e 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h | |||
@@ -1296,7 +1296,14 @@ int ide_in_drive_list(struct hd_driveid *, const struct drive_list_entry *); | |||
1296 | #ifdef CONFIG_BLK_DEV_IDEDMA | 1296 | #ifdef CONFIG_BLK_DEV_IDEDMA |
1297 | int __ide_dma_bad_drive(ide_drive_t *); | 1297 | int __ide_dma_bad_drive(ide_drive_t *); |
1298 | int __ide_dma_good_drive(ide_drive_t *); | 1298 | int __ide_dma_good_drive(ide_drive_t *); |
1299 | u8 ide_max_dma_mode(ide_drive_t *); | 1299 | |
1300 | u8 ide_find_dma_mode(ide_drive_t *, u8); | ||
1301 | |||
1302 | static inline u8 ide_max_dma_mode(ide_drive_t *drive) | ||
1303 | { | ||
1304 | return ide_find_dma_mode(drive, XFER_UDMA_6); | ||
1305 | } | ||
1306 | |||
1300 | int ide_tune_dma(ide_drive_t *); | 1307 | int ide_tune_dma(ide_drive_t *); |
1301 | void ide_dma_off(ide_drive_t *); | 1308 | void ide_dma_off(ide_drive_t *); |
1302 | void ide_dma_verbose(ide_drive_t *); | 1309 | void ide_dma_verbose(ide_drive_t *); |
@@ -1322,6 +1329,7 @@ extern void ide_dma_timeout(ide_drive_t *); | |||
1322 | #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ | 1329 | #endif /* CONFIG_BLK_DEV_IDEDMA_PCI */ |
1323 | 1330 | ||
1324 | #else | 1331 | #else |
1332 | static inline u8 ide_find_dma_mode(ide_drive_t *drive, u8 speed) { return 0; } | ||
1325 | static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; } | 1333 | static inline u8 ide_max_dma_mode(ide_drive_t *drive) { return 0; } |
1326 | static inline int ide_tune_dma(ide_drive_t *drive) { return 0; } | 1334 | static inline int ide_tune_dma(ide_drive_t *drive) { return 0; } |
1327 | static inline void ide_dma_off(ide_drive_t *drive) { ; } | 1335 | static inline void ide_dma_off(ide_drive_t *drive) { ; } |