[LinuxBIOS] filo ide speedup patch!
Peter Stuge
stuge-linuxbios at cdy.org
Mon Mar 26 03:42:08 CEST 2007
Sorry for the delays here..
On Tue, Mar 20, 2007 at 03:43:46PM +0100, Stefan Reinauer wrote:
> * Peter Stuge <stuge-linuxbios at cdy.org> [070320 04:35]:
> > Please test this patch. Note I have only implemented multiread
> > support in fsys_ext2fs.c.
>
> I am getting "Can't read kernel" on a CF:
>
> hda: LBA 128MB: TRANSCEND DOM128M
On Tue, Mar 20, 2007 at 10:09:39AM -0400, Ward Vandewege wrote:
> Hmm, that doesn't seem to work. This is what's in my grub stanza to
> boot with an umodified filo:
>
> title Ubuntu LB, kernel 2.6.21-rc3
> root (hd4,0)
> kernel /boot/vmlinuz-2.6.21-rc3 root=/dev/sda1 ro apic=debug
> acpi_dbg_level=0xffffffff pci=noacpi,routeirq
> snd-hda-intel.enable_msi=1
> console=tty0 console=ttyS0,115200
> savedefault
> boot
>
> I've attached the boot log.
You're booting FILO from GRUB? Ok.
> load_linux_kernel: offset=0x1e00 addr=0x100000 size=0x1d1473
> Loading kernel... Can't read kernel
Same error as Stefan; FILO did not get enough bytes back from the
filesystem.
I've added debugging output with this patch, please test this patch
with DEBUG_BLOCKDEV, DEBUG_IDE and DEBUG_EXT2 (or DEBUG_ALL) set so
I can get more details.
Unfortunately my own EPIA-MII board doesn't run anymore (blown GSC
capacitors) so I haven't been able to test it myself.
Otherwise no new code since last patch. Please enable this debugging
output (DEBUG_ALL=1 is easiest) and send it to the list.
The debugging was added back in a hurry and since I can't test I may
need to send yet another patch if there's something missing.
No sign-off this time.
//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: 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,7 +403,46 @@
int map;
int ret = 0;
int size = 0;
+ int manylen,manypos,blocks,mapped;
+ /* read one full or partial device block */
+ int ext2fs_read_one(void) {
+ if (map < 0)
+ return 1;
+ size = E2_BSIZE;
+ size -= offset;
+ if (size > len)
+ size = len;
+ disk_read_func = disk_read_hook;
+ devread (map * (E2_BSIZE/DEV_BSIZE), offset, size, buf);
+ disk_read_func = NULL;
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ return 0;
+ }
+
+ /* read several full fs blocks at once */
+ int ext2fs_read_many(int first_block, int num_blocks) {
+ int first_devblock, num_devblocks;
+ 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;
+ devreadmany (buf, first_devblock, num_devblocks);
+ disk_read_func = NULL;
+ size = num_blocks * E2_BSIZE;
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ return 0;
+ }
+
#ifdef E2DEBUG
static char hexdigit[] = "0123456789abcdef";
unsigned char *i;
@@ -415,6 +462,50 @@
}
}
#endif /* E2DEBUG */
+
+ /* read up to 128 blocks (256 sectors) at once */
+ if(len > (2 * DEV_BSIZE))
+ {
+ 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;
+ }
+ blocks = 0;
+ mapped = -2; /* make sure the for loop condition starts out true */
+ while( len >= E2_BSIZE)
+ {
+ manylen = len;
+ manypos = filepos;
+ for(blocks = 0; manylen >= E2_BSIZE && blocks < 128; blocks++)
+ {
+ map = ext2fs_block_map (manypos >> EXT2_BLOCK_SIZE_BITS (SUPERBLOCK));
+ if (blocks > 0 && map != mapped + blocks)
+ break;
+ if (!blocks)
+ mapped = map;
+ if (manylen < E2_BSIZE)
+ continue;
+ manypos += E2_BSIZE;
+ manylen -= E2_BSIZE;
+ }
+ debug ("%3d consecutive blocks %d - %d len=%d ret=%d\n", blocks, mapped, mapped + blocks - 1, len, ret);
+ if (ext2fs_read_many (mapped, blocks))
+ goto err;
+ }
+ if(len > 0)
+ {
+ map = mapped + blocks;
+ debug ("reading final block %d len=%d ret=%d\n", map, len, ret);
+ if (ext2fs_read_one ())
+ goto err;
+ }
+ debug ("done reading many len=%d ret=%d\n", len, ret);
+ }
+
while (len > 0)
{
/* find the (logical) block component of our location */
@@ -424,27 +515,11 @@
#ifdef E2DEBUG
printf ("map=%d\n", map);
#endif /* E2DEBUG */
- if (map < 0)
- break;
-
- size = EXT2_BLOCK_SIZE (SUPERBLOCK);
- size -= offset;
- if (size > len)
- size = len;
-
- 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 (ext2fs_read_one ())
+ break;
}
+err:
if (errnum)
ret = 0;
Index: fs/blockdev.c
===================================================================
--- fs/blockdev.c (revision 34)
+++ fs/blockdev.c (working copy)
@@ -335,6 +335,50 @@
return 0;
}
+/* reads many sectors from opened device into a buffer */
+static int read_manysectors(char *buf, unsigned long first_sector, unsigned long num_sectors)
+{
+ /* If reading memory, just copy into the buffer */
+ 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:
+ if (ide_readmany(dev_drive, first_sector, num_sectors, buf) != 0)
+ goto readerr;
+ 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 +413,22 @@
}
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("last_sector=%lu part_length=%lu\n", last_sector, part_length);
+ return 0;
+ }
+
+ debug("devreadmany %lu - %lu to %p\n", first_sector, first_sector + num_sectors - 1, buf);
+ if (!read_manysectors (dest, part_start + first_sector, num_sectors)) {
+ debug("read many sectors failed\n");
+ 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,16 +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;
- }
+
+ /* 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)) {
+ print_status(ctrl);
+ return -1;
+ }
+ insw(IDE_REG_DATA(ctrl), buffer, count/2);
+ buffer += count;
+ bytes -= count;
+ ndelay(400);
+ } while(bytes);
+
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;
@@ -456,8 +477,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 +487,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 +506,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 +529,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 +551,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 +599,30 @@
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;
- //debug("drive=%d, sector=%ld\n",drive,(unsigned long) sector);
/* Report the buffer is empty */
- if (sector > info->sectors) {
+ if (first_sector + num_sectors - 1 > info->sectors) {
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 +630,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