[U-Boot] [PATCH] IDE: Improving speed on reading data Part 1/1

Jean-Christophe PLAGNIOL-VILLARD plagnioj at jcrosoft.com
Sun Jan 4 08:47:02 CET 2009


On 22:22 Tue 16 Dec     , Stefan Althoefer wrote:
> IDE: Improving speed on reading data
> 
> This patch improves the speed when reading blocks from
> IDE devices by reading more than one block at a time. Up to
> 128 blocks are requested in one read command.
> 
> The ide_wait() code was rewritten to have lower latency
> by polling more frequently for status.
> 
> On my testplatform (Janz emPC-A400 with CompactFLASH card)
> this nearly doubled speed.
> 
> Also, error handling has been improved, so that ide_read does not
> attempt to read beyond the last sector of the device.
> 
> Signed-off-by: Stefan Althoefer <stefan.althoefer at web.de>
> ---
> > Can you please use git-format-patch to format the patch? I don't know
> > how you created the diff, but it looks strange to me (and harldy
> > readable).
> 
> Sorry I wasn't fully aware of the wonderful world of git-* when
> I prepared the first patches ... ok I'm still not (fully).
> 
> >> -		ide_outb (device, ATA_SECT_CNT, 1);
> >> +		scnt = (blkcnt > 128) ? 128 : blkcnt;
> >> +		ide_outb (device, ATA_SECT_CNT, scnt);
> >
> > What happens if you try to read at or beyond the end of the device?
> 
> Good point. The old code wasn't very smart with this either (it did not
> check for bounds but let the device decide). My code added a deadlock
> to this behaviour (break did not work in a inner loop).
> 
> I added some checks against block_dev_desc_t->lba to fix this.
please send patch as a separate e-mail or put the comment which will not
appear in the commit message after the ---
> 
>  common/cmd_ide.c |   63 ++++++++++++++++++++++++++++++++++-------------------
>  1 files changed, 40 insertions(+), 23 deletions(-)
> 
> diff --git a/common/cmd_ide.c b/common/cmd_ide.c
> index dd62c87..ec64767 100644
> --- a/common/cmd_ide.c
> +++ b/common/cmd_ide.c
> @@ -1361,6 +1361,8 @@ ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
>  	ulong n = 0;
>  	unsigned char c;
>  	unsigned char pwrsave=0; /* power save */
> +	ulong scnt;
> +	lbaint_t blkrem;
>  #ifdef CONFIG_LBA48
>  	unsigned char lba48 = 0;
> 
> @@ -1372,6 +1374,12 @@ ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
>  	debug ("ide_read dev %d start %qX, blocks %lX buffer at %lX\n",
>  		device, blknr, blkcnt, (ulong)buffer);
> 
> +	if( blknr >= ide_get_dev(device)->lba ){
please replace with
	if (blknr >= ide_get_dev(device)->lba) {

> +		printf ("IDE read: device %d read beyond last block\n", device);
> +		goto IDE_READ_E;
> +	}
> +	blkrem = ide_get_dev(device)->lba - blknr;
> +
>  	ide_led (DEVICE_LED(device), 1);	/* LED on	*/
> 
>  	/* Select device
> @@ -1405,7 +1413,7 @@ ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
>  	}
> 
> 
> -	while (blkcnt-- > 0) {
> +	while (blkcnt > 0) {
> 
>  		c = ide_wait (device, IDE_TIME_OUT);
> 
> @@ -1427,7 +1435,9 @@ ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
>  #endif
>  		}
>  #endif
> -		ide_outb (device, ATA_SECT_CNT, 1);
> +		scnt = (blkcnt > 128) ? 128 : blkcnt;
> +		scnt = (scnt > blkrem) ? blkrem : scnt;
> +		ide_outb (device, ATA_SECT_CNT, scnt);
>  		ide_outb (device, ATA_LBA_LOW,  (blknr >>  0) & 0xFF);
>  		ide_outb (device, ATA_LBA_MID,  (blknr >>  8) & 0xFF);
>  		ide_outb (device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
> @@ -1446,32 +1456,39 @@ ulong ide_read (int device, lbaint_t blknr, ulong blkcnt, void *buffer)
>  			ide_outb (device, ATA_COMMAND,  ATA_CMD_READ);
>  		}
> 
> -		udelay (50);
> +		while (scnt > 0) {
> +			udelay (50);
> 
> -		if(pwrsave) {
> -			c = ide_wait (device, IDE_SPIN_UP_TIME_OUT);	/* may take up to 4 sec */
> -			pwrsave=0;
> -		} else {
> -			c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
> -		}
> +			if(pwrsave) {
> +				c = ide_wait (device, IDE_SPIN_UP_TIME_OUT);	/* may take up to 4 sec */
> +				pwrsave=0;
please add a space before and after the '='
add be carefull of the 80 chars limit
> +			} else {
> +				c = ide_wait (device, IDE_TIME_OUT);	/* can't take over 500 ms */
> +			}
> 
> -		if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
> +			if ((c&(ATA_STAT_DRQ|ATA_STAT_BUSY|ATA_STAT_ERR)) != ATA_STAT_DRQ) {
please add a space before and after the '&' and '|'
>  #if defined(CONFIG_SYS_64BIT_LBA) && defined(CONFIG_SYS_64BIT_VSPRINTF)
> -			printf ("Error (no IRQ) dev %d blk %qd: status 0x%02x\n",
> -				device, blknr, c);
> +				printf ("Error (no IRQ) dev %d blk %qd: status 0x%02x\n",
> +					device, blknr, c);
>  #else
> -			printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
> -				device, (ulong)blknr, c);
> +				printf ("Error (no IRQ) dev %d blk %ld: status 0x%02x\n",
> +					device, (ulong)blknr, c);
>  #endif
> -			break;
> -		}
> +				goto IDE_READ_E;
> +			}
> 
> -		input_data (device, buffer, ATA_SECTORWORDS);
> -		(void) ide_inb (device, ATA_STATUS);	/* clear IRQ */
> +			input_data (device, buffer, ATA_SECTORWORDS);
> +			(void) ide_inb (device, ATA_STATUS);	/* clear IRQ */
> 
> -		++n;
> -		++blknr;
> -		buffer += ATA_BLOCKSIZE;
> +			++n;
> +			++blknr;
> +			--blkcnt;
> +			--blkrem;
> +			--scnt;
> +			buffer += ATA_BLOCKSIZE;
> +		}
> +		if (blkrem == 0)
> +			break;
>  	}
>  IDE_READ_E:
>  	ide_led (DEVICE_LED(device), 0);	/* LED off	*/
> @@ -1607,11 +1624,11 @@ OUT:
>   */
>  static uchar ide_wait (int dev, ulong t)
>  {
> -	ulong delay = 10 * t;		/* poll every 100 us */
> +	ulong delay = (1000/5) * t;		/* poll every 5 us */
why not 200 instead?
>  	uchar c;
> 
>  	while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
> -		udelay (100);
> +		udelay (5);
>  		if (delay-- == 0) {
>  			break;
>  		}
Best Regards,
J.


More information about the U-Boot mailing list