summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2009-10-08 07:15:08 +0000
committerChris Johns <chrisj@rtems.org>2009-10-08 07:15:08 +0000
commitc1fc5d470913c6824f2ab673c9d69e7d3920a4df (patch)
treec29677690b67d713759d6b0a4864a4f487b17686 /c
parent2009-10-08 Chris Johns <chrisj@rtems.org> (diff)
downloadrtems-c1fc5d470913c6824f2ab673c9d69e7d3920a4df.tar.bz2
2009-10-08 Chris Johns <chrisj@rtems.org>
* ide/ide.c: Fixed more IDE driver bugs. The driver can transfer 64K in a single write on my test PC and qemu with this driver. The driver only checks the data ready bit at the start of each 512 block being transfered. This has speed the transfer loop up. Fixed the timing so the BSP timer is used until RTEMS has started.
Diffstat (limited to 'c')
-rw-r--r--c/src/lib/libbsp/i386/pc386/ChangeLog8
-rw-r--r--c/src/lib/libbsp/i386/pc386/ide/ide.c376
2 files changed, 287 insertions, 97 deletions
diff --git a/c/src/lib/libbsp/i386/pc386/ChangeLog b/c/src/lib/libbsp/i386/pc386/ChangeLog
index 941fcb9c0f..a02aa5908a 100644
--- a/c/src/lib/libbsp/i386/pc386/ChangeLog
+++ b/c/src/lib/libbsp/i386/pc386/ChangeLog
@@ -1,3 +1,11 @@
+2009-10-08 Chris Johns <chrisj@rtems.org>
+
+ * ide/ide.c: Fixed more IDE driver bugs. The driver can transfer
+ 64K in a single write on my test PC and qemu with this driver. The
+ driver only checks the data ready bit at the start of each 512
+ block being transfered. This has speed the transfer loop up. Fixed
+ the timing so the BSP timer is used until RTEMS has started.
+
2009-09-30 Ralf Corsépius <ralf.corsepius@rtems.org>
* console/console.c, console/serial_mouse.c: Reflect
diff --git a/c/src/lib/libbsp/i386/pc386/ide/ide.c b/c/src/lib/libbsp/i386/pc386/ide/ide.c
index a43f796d11..b7850fab10 100644
--- a/c/src/lib/libbsp/i386/pc386/ide/ide.c
+++ b/c/src/lib/libbsp/i386/pc386/ide/ide.c
@@ -29,51 +29,125 @@
#include <libchip/ide_ctrl_cfg.h>
#include <libchip/ide_ctrl_io.h>
+#define ATA_SECTOR_SIZE (512)
+
+/*
+ * Use during initialisation.
+ */
+extern void Wait_X_ms(unsigned int msecs);
+
bool pc386_ide_show;
+uint32_t pc386_ide_timeout;
+
+#define PC386_IDE_DEBUG_OUT 0
+
+#if PC386_IDE_DEBUG_OUT
+bool pc386_ide_trace;
+#define pc386_ide_printk if (pc386_ide_trace) printk
+#endif
+
+#define PC386_IDE_PROBE_TIMEOUT (500)
+#define PC386_IDE_PRESTART_TIMEOUT (1000)
+#define PC386_IDE_TASKING_TIMEOUT (2000)
+
+/*
+ * Prestart sleep using a calibrated timing loop.
+ */
+static void pc386_ide_prestart_sleep (void)
+{
+ Wait_X_ms (10);
+}
+
+/*
+ * Once tasking has started we use a task sleep.
+ */
+static void pc386_ide_tasking_sleep (void)
+{
+ rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (10000) ?
+ TOD_MICROSECONDS_TO_TICKS (10000) : 1);
+}
+
+typedef void (*pc386_ide_sleeper)(void);
+
+static void pc386_ide_sleep (pc386_ide_sleeper sleeper)
+{
+ sleeper ();
+}
-/* #define DEBUG_OUT */
+static void wait(volatile uint32_t loops)
+{
+ while (loops)
+ loops--;
+}
-static bool pc386_ide_status_busy (uint32_t port,
- uint32_t timeout,
- uint8_t* status_val)
+static bool pc386_ide_status_busy (uint32_t port,
+ volatile uint32_t timeout,
+ uint8_t* status_val,
+ pc386_ide_sleeper sleeper)
{
+ volatile uint8_t status;
+ int polls;
+
do
{
- inport_byte (port + IDE_REGISTER_STATUS, *status_val);
- if ((*status_val & IDE_REGISTER_STATUS_BSY) == 0)
- return true;
+ polls = 500;
+ while (polls)
+ {
+ inport_byte (port + IDE_REGISTER_STATUS, status);
+ if ((status & IDE_REGISTER_STATUS_BSY) == 0)
+ {
+ *status_val = status;
+ return true;
+ }
+ polls--;
+ }
if (timeout)
{
timeout--;
- rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (1000));
+ pc386_ide_sleep (sleeper);
}
}
while (timeout);
+ *status_val = status;
return false;
}
-static bool pc386_ide_status_data_ready (uint32_t port,
- uint32_t timeout,
- uint8_t* status_val)
+static bool pc386_ide_status_data_ready (uint32_t port,
+ volatile uint32_t timeout,
+ uint8_t* status_val,
+ pc386_ide_sleeper sleeper)
{
+ volatile uint8_t status;
+ int polls;
+
do
{
- inport_byte (port + IDE_REGISTER_STATUS, *status_val);
+ polls = 1000;
+ while (polls)
+ {
+ inport_byte (port + IDE_REGISTER_STATUS, status);
- if (((*status_val & IDE_REGISTER_STATUS_BSY) == 0) &&
- (*status_val & IDE_REGISTER_STATUS_DRQ))
- return true;
+ if (((status & IDE_REGISTER_STATUS_BSY) == 0) &&
+ (status & IDE_REGISTER_STATUS_DRQ))
+ {
+ *status_val = status;
+ return true;
+ }
+
+ polls--;
+ }
if (timeout)
{
timeout--;
- rtems_task_wake_after (TOD_MICROSECONDS_TO_TICKS (1000));
+ pc386_ide_sleep (sleeper);
}
}
while (timeout);
+ *status_val = status;
return false;
}
@@ -103,12 +177,6 @@ bool pc386_ide_probe
return ide_card_plugged;
}
-static void wait(volatile uint32_t loops)
-{
- while (loops)
- loops--;
-}
-
/*=========================================================================*\
| Function: |
\*-------------------------------------------------------------------------*/
@@ -151,9 +219,14 @@ void pc386_ide_initialize
uint8_t cyllsb;
uint8_t cylmsb;
const char* label = dev ? " slave" : "master";
+ int max_multiple_sectors = 0;
+ int cur_multiple_sectors = 0;
+ uint32_t cylinders = 0;
+ uint32_t heads = 0;
+ uint32_t sectors = 0;
char model_number[41];
char* p = &model_number[0];
-
+
memset(model_number, 0, sizeof(model_number));
outport_byte(port+IDE_REGISTER_DEVICE_HEAD,
@@ -165,7 +238,8 @@ void pc386_ide_initialize
outport_byte(port+IDE_REGISTER_COMMAND, 0x00);
- if (!pc386_ide_status_busy (port, 6000, &status))
+ if (!pc386_ide_status_busy (port, PC386_IDE_PROBE_TIMEOUT,
+ &status, pc386_ide_prestart_sleep))
continue;
inport_byte(port+IDE_REGISTER_STATUS, status);
@@ -181,39 +255,26 @@ void pc386_ide_initialize
printk("IDE%d:%s: cylinder-high=%02x\n", minor, label, cylmsb);
}
-#if 0
- /*
- * Filter based on the cylinder values and the status.
- * Taken from grub's ata.c.
- */
- if (cyllsb != 0x14 || cylmsb != 0xeb)
- if (status == 0 || (cyllsb != 0 && cylmsb != 0 &&
- cyllsb != 0xc3 && cylmsb != 0x3c))
- {
- if (pc386_ide_show)
- printk("IDE%d:%s: bad device\n", minor, label);
- }
-#endif
-
outport_byte(port+IDE_REGISTER_COMMAND, 0xec);
- if (!pc386_ide_status_busy (port, 6000, &status))
+ if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
+ &status, pc386_ide_prestart_sleep))
{
if (pc386_ide_show)
printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
continue;
}
-
+
byte = 0;
while (byte < 512)
{
uint16_t word;
bool data_ready;
- if (pc386_ide_show && ((byte % 16) == 0))
- printk("\n %04x : ", byte);
-
- data_ready = pc386_ide_status_data_ready (port, 100, &status);
+ data_ready = pc386_ide_status_data_ready (port,
+ 250,
+ &status,
+ pc386_ide_prestart_sleep);
if (status & IDE_REGISTER_STATUS_ERR)
{
@@ -234,11 +295,21 @@ void pc386_ide_initialize
if (!data_ready)
break;
+ if (pc386_ide_show && ((byte % 16) == 0))
+ printk("\n %04x : ", byte);
+
inport_word(port+IDE_REGISTER_DATA, word);
if (pc386_ide_show)
printk ("%04x ", word);
+ if (byte == 2)
+ cylinders = word;
+ if (byte == 6)
+ heads = word;
+ if (byte == 12)
+ sectors = word;
+
if (byte >= 54 && byte < (54 + 40))
{
*p = word >> 8;
@@ -246,7 +317,19 @@ void pc386_ide_initialize
*p = word;
p++;
}
-
+
+ if (byte == 94)
+ max_multiple_sectors = word & 0xff;
+
+ if (byte == (47 * 2))
+ max_multiple_sectors = word & 0xff;
+
+ if (byte == (59 * 2))
+ {
+ if (word & (1 << 8))
+ cur_multiple_sectors = word & 0xff;
+ }
+
byte += 2;
}
@@ -254,8 +337,78 @@ void pc386_ide_initialize
printk("\nbytes read = %d\n", byte);
if (p != &model_number[0])
- printk("IDE%d:%s: %s\n", minor, label, model_number);
+ {
+ uint32_t size;
+ uint32_t left;
+ uint32_t right;
+ char units;
+
+ size = ((((uint64_t) cylinders) * heads) * sectors * 512) / 1024;
+
+ if (size > (1024 * 1024))
+ {
+ size = (size * 10) / (1000 * 1000);
+ units = 'G';
+ }
+ else if (size > 1024)
+ {
+ size = (size * 10) / 1000;
+ units = 'M';
+ }
+ else
+ {
+ size = size * 10;
+ units = 'K';
+ }
+
+ left = size / 10;
+ right = size % 10;
+
+ p--;
+ while (*p == ' ')
+ {
+ *p = '\0';
+ p--;
+ }
+
+ printk("IDE%d:%s:%s, %u.%u%c (%u/%u/%u), max blk size:%d\n",
+ minor, label, model_number, left, right, units,
+ heads, cylinders, sectors, max_multiple_sectors * 512);
+ }
+
+#if IDE_CLEAR_MULTI_SECTOR_COUNT
+ if (max_multiple_sectors)
+ {
+ outport_byte(port+IDE_REGISTER_SECTOR_COUNT, 0);
+ outport_byte(port+IDE_REGISTER_COMMAND, 0xc6);
+
+ if (!pc386_ide_status_busy (port, PC386_IDE_PRESTART_TIMEOUT,
+ &status, pc386_ide_prestart_sleep))
+ {
+ if (pc386_ide_show)
+ printk("IDE%d:%s: device busy: %02x\n", minor, label, status);
+ continue;
+ }
+
+ inport_byte(port+IDE_REGISTER_STATUS, status);
+ if (status & IDE_REGISTER_STATUS_ERR)
+ {
+ inport_byte(port+IDE_REGISTER_ERROR, error);
+ if (error & IDE_REGISTER_ERROR_ABRT)
+ printk("IDE%d:%s: disable multiple failed\n", minor, label);
+ else
+ printk("IDE%d:%s: unknown error on disable multiple: %02x\n",
+ minor, label, error);
+ }
+ }
+#endif
+
+ outport_byte(port+IDE_REGISTER_DEVICE_CONTROL,
+ IDE_REGISTER_DEVICE_CONTROL_nIEN);
+ wait(10000);
}
+
+ pc386_ide_timeout = PC386_IDE_TASKING_TIMEOUT;
/*
* FIXME: enable interrupts, if needed
@@ -294,8 +447,8 @@ void pc386_ide_read_reg
inport_byte(port+reg, bval1);
*value = bval1;
}
-#ifdef DEBUG_OUT
- printk("pc386_ide_read_reg (0x%x)=0x%x\r\n",reg,*value & 0xff);
+#if PC386_IDE_DEBUG_OUT
+ pc386_ide_printk("pc386_ide_read_reg (0x%x)=0x%x\r\n",reg,*value & 0xff);
#endif
}
@@ -321,8 +474,8 @@ void pc386_ide_write_reg
{
uint32_t port = IDE_Controller_Table[minor].port1;
-#ifdef DEBUG_OUT
- printk("pc386_ide_write_reg(0x%x,0x%x)\r\n",reg,value & 0xff);
+#if PC386_IDE_DEBUG_OUT
+ pc386_ide_printk("pc386_ide_write_reg(0x%x,0x%x)\r\n",reg,value & 0xff);
#endif
if (reg == IDE_REGISTER_DATA_WORD) {
outport_word(port+reg,value);
@@ -343,8 +496,8 @@ void pc386_ide_read_block
+---------------------------------------------------------------------------+
| Input Parameters: |
\*-------------------------------------------------------------------------*/
- int minor,
- uint16_t block_size,
+ int minor,
+ uint32_t block_size,
rtems_blkdev_sg_buffer *bufs,
uint32_t *cbuf,
uint32_t *pos
@@ -354,47 +507,59 @@ void pc386_ide_read_block
| <none> |
\*=========================================================================*/
{
- uint32_t port = IDE_Controller_Table[minor].port1;
- uint16_t cnt = 0;
- uint32_t llength = bufs[(*cbuf)].length;
- uint8_t status_val;
- uint16_t *lbuf = (uint16_t*)
- ((uint8_t*)(bufs[(*cbuf)].buffer) + (*pos));
-#ifdef DEBUG_OUT
+ uint32_t port = IDE_Controller_Table[minor].port1;
+ uint32_t cnt = 0;
+#if PC386_IDE_DEBUG_OUT
int i32 = 0;
+ pc386_ide_printk("pc386_ide_read_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
+ block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
#endif
+
while (cnt < block_size)
{
- if (!pc386_ide_status_data_ready (port, 100, &status_val))
+ uint16_t *lbuf;
+ uint8_t status_val;
+ int b;
+
+ if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
+ &status_val, pc386_ide_tasking_sleep))
{
- printk ("pc386_ide_read_block: status=%02x, cnt=%d bs=%d\n", status_val, cnt, block_size);
+ printk ("pc386_ide_read_block: block=%u cbuf=%u status=%02x, cnt=%d bs=%d\n",
+ bufs[*cbuf].block, *cbuf, status_val, cnt, block_size);
/* FIXME: add an error here. */
return;
}
if (status_val & IDE_REGISTER_STATUS_ERR)
+ {
+ inport_byte(port+IDE_REGISTER_ERROR, status_val);
printk("pc386_ide_read_block: error: %02x\n", status_val);
-
- inport_word(port+IDE_REGISTER_DATA,*lbuf);
+ return;
+ }
-#ifdef DEBUG_OUT
- printk("%04x ",*lbuf);
- i32++;
- if (i32 >= 16)
+ lbuf = (uint16_t*)((uint8_t*)(bufs[(*cbuf)].buffer) + (*pos));
+
+ for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
{
- printk("\n");
- i32 = 0;
- }
+ inport_word(port+IDE_REGISTER_DATA,*lbuf);
+
+#if PC386_IDE_DEBUG_OUT
+ pc386_ide_printk("%04x ",*lbuf);
+ i32++;
+ if (i32 >= 16)
+ {
+ pc386_ide_printk("\n");
+ i32 = 0;
+ }
#endif
-
- lbuf++;
- cnt += sizeof(*lbuf);
- (*pos) += sizeof(*lbuf);
- if ((*pos) == llength) {
+ lbuf++;
+ }
+ cnt += ATA_SECTOR_SIZE;
+ (*pos) += ATA_SECTOR_SIZE;
+ if ((*pos) == bufs[(*cbuf)].length) {
(*pos) = 0;
(*cbuf)++;
lbuf = bufs[(*cbuf)].buffer;
- llength = bufs[(*cbuf)].length;
}
}
}
@@ -411,7 +576,7 @@ void pc386_ide_write_block
| Input Parameters: |
\*-------------------------------------------------------------------------*/
int minor,
- uint16_t block_size,
+ uint32_t block_size,
rtems_blkdev_sg_buffer *bufs,
uint32_t *cbuf,
uint32_t *pos
@@ -421,41 +586,58 @@ void pc386_ide_write_block
| <none> |
\*=========================================================================*/
{
- uint32_t port = IDE_Controller_Table[minor].port1;
- uint16_t cnt = 0;
- uint32_t llength = bufs[(*cbuf)].length;
- uint8_t status_val;
- uint16_t *lbuf = (uint16_t*)
- ((uint8_t*)(bufs[(*cbuf)].buffer) + (*pos));
-
-#ifdef DEBUG_OUT
- printk("pc386_ide_write_block()\n");
+ uint32_t port = IDE_Controller_Table[minor].port1;
+ uint32_t cnt = 0;
+#if PC386_IDE_DEBUG_OUT
+ int i32 = 0;
+ pc386_ide_printk("pc386_ide_write_block(bs=%u,bn=%u,bl=%u,cb=%d,p=%d)\n",
+ block_size, bufs[(*cbuf)].block, llength, *cbuf, *pos);
#endif
while (cnt < block_size)
{
- if (!pc386_ide_status_data_ready (port, 100, &status_val))
+ uint16_t *lbuf;
+ uint8_t status_val;
+ int b;
+
+ if (!pc386_ide_status_data_ready (port, pc386_ide_timeout,
+ &status_val, pc386_ide_tasking_sleep))
{
- printk ("pc386_ide_write_block: status=%02x, cnt=%d bs=%d\n", status_val, cnt, block_size);
+ printk ("pc386_ide_write_block: block=%u status=%02x, cnt=%d bs=%d\n",
+ bufs[*cbuf].block, status_val, cnt, block_size);
/* FIXME: add an error here. */
return;
}
if (status_val & IDE_REGISTER_STATUS_ERR)
- printk("pc386_ide_write_block: error: %02x\n", status_val);
+ {
+ inport_byte(port+IDE_REGISTER_ERROR, status_val);
+ printk ("pc386_ide_write_block: error: %02x\n", status_val);
+ return;
+ }
-#ifdef DEBUG_OUT
- printk("0x%x ",*lbuf);
+ lbuf = (uint16_t*)(((uint8_t*)bufs[*cbuf].buffer) + (*pos));
+
+ for (b = 0; b < (ATA_SECTOR_SIZE / 2); b++)
+ {
+#if PC386_IDE_DEBUG_OUT
+ pc386_ide_printk("%04x ",*lbuf);
+ i32++;
+ if (i32 >= 16)
+ {
+ pc386_ide_printk("\n");
+ i32 = 0;
+ }
#endif
- outport_word(port+IDE_REGISTER_DATA,*lbuf);
- lbuf++;
- cnt += sizeof(*lbuf);
- (*pos) += sizeof(*lbuf);
- if ((*pos) == llength) {
+ outport_word(port+IDE_REGISTER_DATA,*lbuf);
+ lbuf++;
+ }
+ cnt += ATA_SECTOR_SIZE;
+ (*pos) += ATA_SECTOR_SIZE;
+ if ((*pos) == bufs[(*cbuf)].length) {
(*pos) = 0;
(*cbuf)++;
lbuf = bufs[(*cbuf)].buffer;
- llength = bufs[(*cbuf)].length;
}
}
}