[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