Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d5eaa6d authored by Bartlomiej Zolnierkiewicz's avatar Bartlomiej Zolnierkiewicz
Browse files

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: default avatarBartlomiej Zolnierkiewicz <bzolnier@gmail.com>
parent 18137207
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -342,7 +342,7 @@ static int icside_dma_check(ide_drive_t *drive)
	 * Enable DMA on any drive that has multiword DMA
	 */
	if (id->field_valid & 2) {
		xfer_mode = ide_dma_speed(drive, 0);
		xfer_mode = ide_max_dma_mode(drive);
		goto out;
	}

+1 −1
Original line number Diff line number Diff line
@@ -1004,7 +1004,7 @@ static int cris_ide_build_dmatable (ide_drive_t *drive)

static int cris_config_drive_for_dma (ide_drive_t *drive)
{
	u8 speed = ide_dma_speed(drive, 1);
	u8 speed = ide_max_dma_mode(drive);

	if (!speed)
		return 0;
+74 −0
Original line number Diff line number Diff line
@@ -705,6 +705,80 @@ int ide_use_dma(ide_drive_t *drive)

EXPORT_SYMBOL_GPL(ide_use_dma);

static const u8 xfer_mode_bases[] = {
	XFER_UDMA_0,
	XFER_MW_DMA_0,
	XFER_SW_DMA_0,
};

static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
{
	struct hd_driveid *id = drive->id;
	ide_hwif_t *hwif = drive->hwif;
	unsigned int mask = 0;

	switch(base) {
	case XFER_UDMA_0:
		if ((id->field_valid & 4) == 0)
			break;

		mask = id->dma_ultra & hwif->ultra_mask;

		if (hwif->udma_filter)
			mask &= hwif->udma_filter(drive);

		if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
			mask &= 0x07;
		break;
	case XFER_MW_DMA_0:
		mask = id->dma_mword & hwif->mwdma_mask;
		break;
	case XFER_SW_DMA_0:
		mask = id->dma_1word & hwif->swdma_mask;
		break;
	default:
		BUG();
		break;
	}

	return mask;
}

/**
 *	ide_max_dma_mode	-	compute DMA speed
 *	@drive: IDE device
 *
 *	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_max_dma_mode(ide_drive_t *drive)
{
	ide_hwif_t *hwif = drive->hwif;
	unsigned int mask;
	int x, i;
	u8 mode = 0;

	if (drive->media != ide_disk && hwif->atapi_dma == 0)
		return 0;

	for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
		mask = ide_get_mode_mask(drive, xfer_mode_bases[i]);
		x = fls(mask) - 1;
		if (x >= 0) {
			mode = xfer_mode_bases[i] + x;
			break;
		}
	}

	printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);

	return mode;
}

EXPORT_SYMBOL_GPL(ide_max_dma_mode);

void ide_dma_verbose(ide_drive_t *drive)
{
	struct hd_driveid *id	= drive->id;
+0 −2
Original line number Diff line number Diff line
@@ -592,8 +592,6 @@ u8 eighty_ninty_three (ide_drive_t *drive)
	return 1;
}

EXPORT_SYMBOL(eighty_ninty_three);

int ide_ata66_check (ide_drive_t *drive, ide_task_t *args)
{
	if ((args->tfRegister[IDE_COMMAND_OFFSET] == WIN_SETFEATURES) &&
+18 −107
Original line number Diff line number Diff line
@@ -69,123 +69,34 @@ char *ide_xfer_verbose (u8 xfer_rate)
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 */
Loading