[LinuxBIOS] filo ide speedup patch!

Peter Stuge stuge-linuxbios at cdy.org
Fri Apr 6 00:40:34 CEST 2007


On Thu, Apr 05, 2007 at 05:27:10PM -0400, Ward Vandewege wrote:
> On Thu, Apr 05, 2007 at 11:26:55PM +0200, Peter Stuge wrote:
> > It's identical. Did the change to drivers/ide.c really take?
> 
> Yeah, verified:

Yep. Looks good.


> I've built the image again to rule out any silly mistakes, and
> still get the same result.

Very strange.

Fresh LB buildtarget and make after rebuilding FILO still uses the
old payload file.. How can that be?

Ok, I've added a little more debugging output and this patch also
contains full error checking.


//Peter
-------------- next part --------------
Index: include/fs.h
===================================================================
--- include/fs.h	(revision 34)
+++ include/fs.h	(working copy)
@@ -7,6 +7,7 @@
 
 #ifdef IDE_DISK
 int ide_probe(int drive);
+int ide_readmany(int drive, sector_t sector, sector_t num_sectors, void *buffer);
 int ide_read(int drive, sector_t sector, void *buffer);
 #endif
 
@@ -22,6 +23,7 @@
 int devopen(const char *name, int *reopen);
 int devread(unsigned long sector, unsigned long byte_offset,
 	unsigned long byte_len, void *buf);
+int devreadmany(void *buf, unsigned long first_sector, unsigned long num_sectors);
 
 int file_open(const char *filename);
 int file_read(void *buf, unsigned long len);
Index: defconfig
===================================================================
--- defconfig	(revision 34)
+++ defconfig	(working copy)
@@ -90,4 +90,5 @@
 #DEBUG_IDE = 1
 #DEBUG_USB = 1
 #DEBUG_ELTORITO = 1
+#DEBUG_EXT2 = 1
 
Index: fs/fsys_ext2fs.c
===================================================================
--- fs/fsys_ext2fs.c	(revision 34)
+++ fs/fsys_ext2fs.c	(working copy)
@@ -1,6 +1,9 @@
 /*
- *  GRUB  --  GRand Unified Bootloader
+ *  FILO ext2fs driver
+ *
+ *  Mostly code from GRUB  --  GRand Unified Bootloader
  *  Copyright (C) 1999, 2001  Free Software Foundation, Inc.
+ *  Copyright (C) 2007  Peter Stuge <peter at stuge.se>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -22,6 +25,9 @@
 #include "shared.h"
 #include "filesys.h"
 
+#define DEBUG_THIS DEBUG_EXT2
+#include <debug.h>
+
 static int mapblock1, mapblock2;
 
 /* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */
@@ -386,6 +392,8 @@
     [logical_block & (EXT2_ADDR_PER_BLOCK (SUPERBLOCK) - 1)];
 }
 
+#define E2_BSIZE (EXT2_BLOCK_SIZE (SUPERBLOCK))
+
 /* preconditions: all preconds of ext2fs_block_map */
 int
 ext2fs_read (char *buf, int len)
@@ -395,26 +403,95 @@
   int map;
   int ret = 0;
   int size = 0;
+  int manylen, manypos, blocks, firstmapped = 0;
 
-#ifdef E2DEBUG
-  static char hexdigit[] = "0123456789abcdef";
-  unsigned char *i;
-  for (i = (unsigned char *) INODE;
-       i < ((unsigned char *) INODE + sizeof (struct ext2_inode));
-       i++)
+  /* read one full or partial block */
+  int ext2fs_read_one(void) {
+    int res;
+    debug ("block  %d  offset=%d len=%d ret=%d\n", map, offset, len, ret);
+    if (map < 0)
+      return 1;
+    size = E2_BSIZE;
+    size -= offset;
+    if (size > len)
+      size = len;
+    disk_read_func = disk_read_hook;
+    res = devread (map * (E2_BSIZE/DEV_BSIZE), offset, size, buf);
+    disk_read_func = NULL;
+    if (!res)
+      return 1;
+    buf += size;
+    len -= size;
+    filepos += size;
+    ret += size;
+    return 0;
+  }
+
+  /* read many fs blocks at once */
+  int ext2fs_read_many(int first_block, int num_blocks) {
+    int first_devblock, num_devblocks, res;
+    debug ("%3d block%c  %d - %d  len=%d ret=%d\n", num_blocks, 1 == num_blocks ? ' ' : 's', first_block, first_block + num_blocks - 1, len, ret);
+    if (offset)
+      debug ("can't read many blocks with non-zero offset %d\n", offset);
+    if (first_block < 0 || num_blocks < 0 || offset)
+      return 1;
+    if (!num_blocks)
+      return 0;
+    first_devblock = first_block * (E2_BSIZE/DEV_BSIZE);
+    num_devblocks = num_blocks * (E2_BSIZE/DEV_BSIZE);
+    disk_read_func = disk_read_hook;
+    res = devreadmany (buf, first_devblock, num_devblocks);
+    disk_read_func = NULL;
+    if (!res)
+      return 1;
+    size = num_blocks * E2_BSIZE;
+    buf += size;
+    len -= size;
+    filepos += size;
+    ret += size;
+    return 0;
+  }
+
+  /* read many blocks at once? */
+  if (len > E2_BSIZE)
     {
-      printf ("%c", hexdigit[*i >> 4]);
-      printf ("%c", hexdigit[*i % 16]);
-      if (!((i + 1 - (unsigned char *) INODE) % 16))
-	{
-	  printf ("\n");
-	}
-      else
-	{
-	  printf (" ");
-	}
+      offset = filepos & (E2_BSIZE-1);
+      if (offset)
+        {
+          logical_block = filepos >> EXT2_BLOCK_SIZE_BITS(SUPERBLOCK);
+          map = ext2fs_block_map (logical_block);
+          if (ext2fs_read_one ())
+            goto err;
+          offset = 0;
+        }
+      while (len > 0)
+        {
+          manylen = len;
+          manypos = filepos;
+          for (blocks = 0; manylen > 0; blocks++)
+            {
+              map = ext2fs_block_map (manypos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK));
+              if (blocks > 0 && map != firstmapped + blocks)
+                break;
+              if (!blocks)
+                firstmapped = map;
+              if (manylen < E2_BSIZE)
+                continue;
+              manypos += E2_BSIZE;
+              manylen -= E2_BSIZE;
+            }
+          if (ext2fs_read_many (firstmapped, blocks))
+            goto err;
+        }
+      if (len < 0)
+        {
+          debug ("discarding %d surplus bytes\n", -len);
+          ret += len;
+          len = 0;
+        }
+      debug ("done reading many  len=%d ret=%d\n", len, ret);
     }
-#endif /* E2DEBUG */
+
   while (len > 0)
     {
       /* find the (logical) block component of our location */
@@ -424,27 +501,14 @@
 #ifdef E2DEBUG
       printf ("map=%d\n", map);
 #endif /* E2DEBUG */
-      if (map < 0)
-	break;
+      if (ext2fs_read_one ())
+        break;
+    }
 
-      size = EXT2_BLOCK_SIZE (SUPERBLOCK);
-      size -= offset;
-      if (size > len)
-	size = len;
+err:
+  if (len)
+    debug ("returning %d with len=%d ret=%d errnum=%d\n", errnum ? 0 : ret, len, ret, errnum);
 
-      disk_read_func = disk_read_hook;
-
-      devread (map * (EXT2_BLOCK_SIZE (SUPERBLOCK) / DEV_BSIZE),
-	       offset, size, buf);
-
-      disk_read_func = NULL;
-
-      buf += size;
-      len -= size;
-      filepos += size;
-      ret += size;
-    }
-
   if (errnum)
     ret = 0;
 
Index: fs/blockdev.c
===================================================================
--- fs/blockdev.c	(revision 34)
+++ fs/blockdev.c	(working copy)
@@ -335,6 +335,58 @@
     return 0;
 }
 
+/* reads many sectors from opened device into memory */
+static unsigned long read_manysectors(char *buf, unsigned long first_sector, unsigned long num_sectors)
+{
+    int n;
+
+    /* If reading memory, just copy it */
+    if (dev_type == DISK_MEM) {
+	unsigned long phys = first_sector << 9;
+	char *virt;
+	//debug("mem: %#lx\n", phys);
+	virt = phys_to_virt(phys);
+	memcpy(buf, virt, num_sectors * 512);
+	return num_sectors;
+    }
+
+    switch (dev_type) {
+#ifdef IDE_DISK
+    case DISK_IDE:
+	do {
+	    n = num_sectors <= 256 ? num_sectors : 256;
+	    if (ide_readmany(dev_drive, first_sector, n, buf) != 0)
+		goto readerr;
+	    first_sector += n;
+	    num_sectors -= n;
+	    buf += 512 * n;
+	} while (num_sectors);
+	break;
+#endif
+#ifdef USB_DISK
+    case DISK_USB:
+	while (num_sectors) {
+	    if (usb_read(dev_drive, first_sector, buf) != 0)
+		goto readerr;
+	    first_sector++;
+	    num_sectors--;
+	    buf += 512;
+	}
+	break;
+#endif
+    default:
+	printf("read_manysectors: device not open\n");
+	return 0;
+    }
+    return 1;
+
+readerr:
+    printf("Disk readmany error dev=%d drive=%d first_sector=%lu num_sectors=%lu\n",
+	    dev_type, dev_drive, first_sector, num_sectors);
+    dev_name[0] = '\0'; /* force re-open the device next time */
+    return 0;
+}
+
 int devread(unsigned long sector, unsigned long byte_offset,
 	unsigned long byte_len, void *buf)
 {
@@ -369,3 +421,21 @@
     }
     return 1;
 }
+
+int devreadmany(void *buf,unsigned long first_sector, unsigned long num_sectors)
+{
+    char *dest = buf;
+    unsigned long last_sector = first_sector + num_sectors - 1;
+
+    if (last_sector > part_length) {
+	printf("Attempt to readmany out of device/partition\n");
+	debug("part_length=%lu last_sector=%lu\n", part_length, last_sector);
+	return 0;
+    }
+
+    debug("sectors %lu - %lu (%3lu) to %p\n", first_sector, last_sector, num_sectors, buf);
+    if (!read_manysectors (dest, part_start + first_sector, num_sectors))
+	return 0;
+
+    return 1;
+}
Index: drivers/ide.c
===================================================================
--- drivers/ide.c	(revision 34)
+++ drivers/ide.c	(working copy)
@@ -19,6 +19,7 @@
  *   UBL, The Universal Talkware Boot Loader 
  *    Copyright (C) 2000 Universal Talkware Inc.
  *    Copyright (C) 2002 Eric Biederman
+ *    Copyright (C) 2007 Peter Stuge <peter at stuge.se>
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
@@ -39,6 +40,7 @@
 struct controller {
 	uint16_t cmd_base;
 	uint16_t ctrl_base;
+	uint8_t stat;
 };
 
 struct harddisk_info {
@@ -255,7 +257,8 @@
 
 static int not_bsy(struct controller *ctrl)
 {
-	return !(inb(IDE_REG_STATUS(ctrl)) & IDE_STATUS_BSY);
+	ctrl->stat=inb(IDE_REG_STATUS(ctrl));
+	return !(ctrl->stat & IDE_STATUS_BSY);
 }
 
 /* IDE drives assert BSY bit within 400 nsec when SRST is set.
@@ -264,7 +267,8 @@
 
 static int bsy(struct controller *ctrl)
 {
-	return inb(IDE_REG_STATUS(ctrl)) & IDE_STATUS_BSY;
+	ctrl->stat=inb(IDE_REG_STATUS(ctrl));
+	return ctrl->stat & IDE_STATUS_BSY;
 }
 
 #if  !BSY_SET_DURING_SPINUP
@@ -364,9 +368,16 @@
 static int pio_data_in(struct controller *ctrl, const struct ide_pio_command *cmd,
 	void *buffer, size_t bytes)
 {
+	int drive;
+	size_t count;
 	unsigned int status;
 
-	/* FIXME handle commands with multiple blocks */
+	for(drive=0; drive < IDE_MAX_DRIVES; drive++)
+		if(ctrl == harddisk_info[drive].ctrl)
+			break;
+	if(IDE_MAX_DRIVES == drive)
+		return -1;
+
 	/* Wait until the busy bit is clear */
 	if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
 		return -1;
@@ -375,20 +386,26 @@
 	/* How do I tell if INTRQ is asserted? */
 	pio_set_registers(ctrl, cmd);
 	ndelay(400);
-	if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0) {
-		return -1;
-	}
-	status = inb(IDE_REG_STATUS(ctrl));
-	if (!(status & IDE_STATUS_DRQ)) {
-		print_status(ctrl);
-		return -1;
-	}
-	insw(IDE_REG_DATA(ctrl), buffer, bytes/2);
-	status = inb(IDE_REG_STATUS(ctrl));
-	if (status & IDE_STATUS_DRQ) {
-		print_status(ctrl);
-		return -1;
-	}
+
+	/* multi block capable logic inspired by OpenBIOS ide.c
+	 * ob_ide_pio_data_in() */
+	do {
+		count = bytes;
+		if (count > harddisk_info[drive].hw_sector_size)
+			count = harddisk_info[drive].hw_sector_size;
+		if (await_ide(not_bsy, ctrl, currticks() + IDE_TIMEOUT) < 0)
+			return -1;
+		if (!(ctrl->stat & IDE_STATUS_DRQ)) {
+			debug("no drq before insw\n");
+			print_status(ctrl);
+			return -1;
+		}
+		insw(IDE_REG_DATA(ctrl), buffer, count/2);
+		buffer += count;
+		bytes -= count;
+		ndelay(400);
+	} while(bytes);
+
 	return 0;
 }
 
@@ -456,8 +473,9 @@
 	return 0;
 }
 
-static inline int ide_read_sector_chs(
-	struct harddisk_info *info, void *buffer, unsigned long sector)
+static inline int ide_read_sectors_chs(
+	struct harddisk_info *info, void *buffer, unsigned long sector,
+	unsigned long num_sectors)
 {
 	struct ide_pio_command cmd;
 	unsigned int track;
@@ -465,8 +483,11 @@
 	unsigned int cylinder;
 		
 	memset(&cmd, 0, sizeof(cmd));
-	cmd.sector_count = 1;
 
+	if (num_sectors > 256)
+		return -1;
+	cmd.sector_count = 256 == num_sectors ? 0 : num_sectors;
+
 	//debug("ide_read_sector_chs: sector= %ld.\n",sector);
 
 	track = sector / info->sectors_per_track;
@@ -481,16 +502,20 @@
 		info->slave |
 		IDE_DH_CHS;
 	cmd.command = IDE_CMD_READ_SECTORS;
-	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE * num_sectors);
 }
 
-static inline int ide_read_sector_lba(
-	struct harddisk_info *info, void *buffer, unsigned long sector)
+static inline int ide_read_sectors_lba(
+	struct harddisk_info *info, void *buffer, unsigned long sector,
+	unsigned long num_sectors)
 {
 	struct ide_pio_command cmd;
 	memset(&cmd, 0, sizeof(cmd));
 
-	cmd.sector_count = 1;
+	if (num_sectors > 256)
+		return -1;
+	cmd.sector_count = 256 == num_sectors ? 0 : num_sectors;
+
 	cmd.lba_low = sector & 0xff;
 	cmd.lba_mid = (sector >> 8) & 0xff;
 	cmd.lba_high = (sector >> 16) & 0xff;
@@ -500,17 +525,20 @@
 		IDE_DH_LBA;
 	cmd.command = IDE_CMD_READ_SECTORS;
 	//debug("%s: sector= %ld, device command= 0x%x.\n",__FUNCTION__,(unsigned long) sector, cmd.device);
-	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE * num_sectors);
 }
 
-static inline int ide_read_sector_lba48(
-	struct harddisk_info *info, void *buffer, sector_t sector)
+static inline int ide_read_sectors_lba48(
+	struct harddisk_info *info, void *buffer, sector_t sector, sector_t num_sectors)
 {
 	struct ide_pio_command cmd;
 	memset(&cmd, 0, sizeof(cmd));
 	//debug("ide_read_sector_lba48: sector= %ld.\n",(unsigned long) sector);
 
-	cmd.sector_count = 1;
+	if (num_sectors > 256)
+		return -1;
+	cmd.sector_count = 256 == num_sectors ? 0 : num_sectors;
+
 	cmd.lba_low = sector & 0xff;
 	cmd.lba_mid = (sector >> 8) & 0xff;
 	cmd.lba_high = (sector >> 16) & 0xff;
@@ -519,7 +547,7 @@
 	cmd.lba_high2 = (sector >> 40) & 0xff;
 	cmd.device =  info->slave | IDE_DH_LBA;
 	cmd.command = IDE_CMD_READ_SECTORS_EXT;
-	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE);
+	return pio_data_in(info->ctrl, &cmd, buffer, IDE_SECTOR_SIZE * num_sectors);
 }
 
 static inline int ide_read_sector_packet(
@@ -567,27 +595,33 @@
 	return 0;
 }
 
-int ide_read(int drive, sector_t sector, void *buffer)
+int ide_readmany(int drive, sector_t first_sector, sector_t num_sectors, void *buffer)
 {
 	struct harddisk_info *info = &harddisk_info[drive];
-	int result;
+	int result, i;
+	sector_t last_sector = first_sector + num_sectors - 1;
 
-	//debug("drive=%d, sector=%ld\n",drive,(unsigned long) sector);
-	/* Report the buffer is empty */
-	if (sector > info->sectors) {
+	if (num_sectors > 1)
+		debug("sectors %Lu - %Lu (%3Lu) to %p\n", first_sector, last_sector, num_sectors, buffer);
+	if (last_sector > info->sectors) {
+		debug("attempt read past end of device");
 		return -1;
 	}
 	if (info->address_mode == ADDRESS_MODE_CHS) {
-		result = ide_read_sector_chs(info, buffer, sector);
+		result = ide_read_sectors_chs(info, buffer, first_sector, num_sectors);
 	}
 	else if (info->address_mode == ADDRESS_MODE_LBA) {
-		result = ide_read_sector_lba(info, buffer, sector);
+		result = ide_read_sectors_lba(info, buffer, first_sector, num_sectors);
 	}
 	else if (info->address_mode == ADDRESS_MODE_LBA48) {
-		result = ide_read_sector_lba48(info, buffer, sector);
+		result = ide_read_sectors_lba48(info, buffer, first_sector, num_sectors);
 	}
 	else if (info->address_mode == ADDRESS_MODE_PACKET) {
-		result = ide_read_sector_packet(info, buffer, sector);
+		for(i = 0; i < num_sectors; i++) {
+			result = ide_read_sector_packet(info, buffer, first_sector);
+			if(-1 == result)
+				return result;
+		}
 	}
 	else {
 		result = -1;
@@ -595,6 +629,11 @@
 	return result;
 }
 
+int ide_read(int drive, sector_t sector, void *buffer)
+{
+	return ide_readmany(drive, sector, 1, buffer);
+}
+
 static int init_drive(struct harddisk_info *info, struct controller *ctrl,
 		int slave, int drive, unsigned char *buffer, int ident_command)
 {


More information about the coreboot mailing list