ide: rework the code for selecting the best DMA transfer mode (v3)
Depends on the "ide: fix UDMA/MWDMA/SWDMA masks" patch.
* add ide_hwif_t.udma_filter hook for filtering UDMA mask
(use it in alim15x3, hpt366, siimage and serverworks drivers)
* add ide_max_dma_mode() for finding best DMA mode for the device
(loosely based on some older libata-core.c code)
* convert ide_dma_speed() users to use ide_max_dma_mode()
* make ide_rate_filter() take "ide_drive_t *drive" as an argument instead
of "u8 mode" and teach it to how to use UDMA mask to do filtering
* use ide_rate_filter() in hpt366 driver
* remove no longer needed ide_dma_speed() and *_ratemask()
* unexport eighty_ninty_three()
v2:
* rename ->filter_udma_mask to ->udma_filter
[ Suggested by Sergei Shtylyov <sshtylyov@ru.mvista.com>. ]
v3:
* updated for scc_pata driver (fixes XFER_UDMA_6 filtering for user-space
originated transfer mode change requests when 100MHz clock is used)
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 6871931..4557fc5 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -69,123 +69,34 @@
EXPORT_SYMBOL(ide_xfer_verbose);
/**
- * ide_dma_speed - compute DMA speed
- * @drive: drive
- * @mode: modes available
- *
- * Checks the drive capabilities and returns the speed to use
- * for the DMA transfer. Returns 0 if the drive is incapable
- * of DMA transfers.
- */
-
-u8 ide_dma_speed(ide_drive_t *drive, u8 mode)
-{
- struct hd_driveid *id = drive->id;
- ide_hwif_t *hwif = HWIF(drive);
- u8 ultra_mask, mwdma_mask, swdma_mask;
- u8 speed = 0;
-
- if (drive->media != ide_disk && hwif->atapi_dma == 0)
- return 0;
-
- /* Capable of UltraDMA modes? */
- ultra_mask = id->dma_ultra & hwif->ultra_mask;
-
- if (!(id->field_valid & 4))
- mode = 0; /* fallback to MW/SW DMA if no UltraDMA */
-
- switch (mode) {
- case 4:
- if (ultra_mask & 0x40) {
- speed = XFER_UDMA_6;
- break;
- }
- case 3:
- if (ultra_mask & 0x20) {
- speed = XFER_UDMA_5;
- break;
- }
- case 2:
- if (ultra_mask & 0x10) {
- speed = XFER_UDMA_4;
- break;
- }
- if (ultra_mask & 0x08) {
- speed = XFER_UDMA_3;
- break;
- }
- case 1:
- if (ultra_mask & 0x04) {
- speed = XFER_UDMA_2;
- break;
- }
- if (ultra_mask & 0x02) {
- speed = XFER_UDMA_1;
- break;
- }
- if (ultra_mask & 0x01) {
- speed = XFER_UDMA_0;
- break;
- }
- case 0:
- mwdma_mask = id->dma_mword & hwif->mwdma_mask;
-
- if (mwdma_mask & 0x04) {
- speed = XFER_MW_DMA_2;
- break;
- }
- if (mwdma_mask & 0x02) {
- speed = XFER_MW_DMA_1;
- break;
- }
- if (mwdma_mask & 0x01) {
- speed = XFER_MW_DMA_0;
- break;
- }
-
- swdma_mask = id->dma_1word & hwif->swdma_mask;
-
- if (swdma_mask & 0x04) {
- speed = XFER_SW_DMA_2;
- break;
- }
- if (swdma_mask & 0x02) {
- speed = XFER_SW_DMA_1;
- break;
- }
- if (swdma_mask & 0x01) {
- speed = XFER_SW_DMA_0;
- break;
- }
- }
-
- return speed;
-}
-EXPORT_SYMBOL(ide_dma_speed);
-
-
-/**
- * ide_rate_filter - return best speed for mode
- * @mode: modes available
+ * ide_rate_filter - filter transfer mode
+ * @drive: IDE device
* @speed: desired speed
*
- * Given the available DMA/UDMA mode this function returns
+ * Given the available transfer modes this function returns
* the best available speed at or below the speed requested.
+ *
+ * FIXME: filter also PIO/SWDMA/MWDMA modes
*/
-u8 ide_rate_filter (u8 mode, u8 speed)
+u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
{
#ifdef CONFIG_BLK_DEV_IDEDMA
- static u8 speed_max[] = {
- XFER_MW_DMA_2, XFER_UDMA_2, XFER_UDMA_4,
- XFER_UDMA_5, XFER_UDMA_6
- };
+ ide_hwif_t *hwif = drive->hwif;
+ u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2;
+
+ if (hwif->udma_filter)
+ mask = hwif->udma_filter(drive);
+
+ if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+ mask &= 0x07;
+
+ if (mask)
+ mode = fls(mask) - 1 + XFER_UDMA_0;
// printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
- /* So that we remember to update this if new modes appear */
- BUG_ON(mode > 4);
- return min(speed, speed_max[mode]);
+ return min(speed, mode);
#else /* !CONFIG_BLK_DEV_IDEDMA */
return min(speed, (u8)XFER_PIO_4);
#endif /* CONFIG_BLK_DEV_IDEDMA */