From: Will Sowerbutts Date: Sun, 11 Jan 2015 23:45:49 +0000 (+0000) Subject: devide: Support for flushing device cache. Avoids sending redundant X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=a78370c30482c630c2522fc0b0c0741397d8ac8c;p=FUZIX.git devide: Support for flushing device cache. Avoids sending redundant flush commands when no blocks have been written since the last flush. --- diff --git a/Kernel/dev/devide.c b/Kernel/dev/devide.c index 5a3bd2d5..f8106d03 100644 --- a/Kernel/dev/devide.c +++ b/Kernel/dev/devide.c @@ -16,6 +16,10 @@ #define DRIVE_COUNT 2 /* range 1 -- 4 */ +static uint8_t drive_flags[DRIVE_COUNT]; +#define FLAG_WRITE_CACHE 1 +#define FLAG_CACHE_DIRTY 2 + #ifdef IDE_REG_ALTSTATUS __sfr __at IDE_REG_ALTSTATUS ide_reg_altstatus; #endif @@ -126,11 +130,36 @@ static bool devide_transfer_sector(uint8_t drive, uint32_t lba, void *buffer, bo devide_write_data(buffer, IDE_REG_DATA); if(!devide_wait(IDE_STATUS_READY)) return false; + drive_flags[drive] |= FLAG_CACHE_DIRTY; } return true; } +static int devide_flush_cache(uint8_t drive) +{ + /* check drive has a cache and was written to since the last flush */ + if(drive_flags[drive] & (FLAG_WRITE_CACHE | FLAG_CACHE_DIRTY) + == (FLAG_WRITE_CACHE | FLAG_CACHE_DIRTY)){ + drive_flags[drive] &= ~FLAG_CACHE_DIRTY; + ide_reg_lba_3 = ((drive == 0) ? 0xE0 : 0xF0); // select drive + + if(!devide_wait(IDE_STATUS_READY)){ + udata.u_error = EIO; + return -1; + } + + ide_reg_command = IDE_CMD_FLUSH_CACHE; + + if(!devide_wait(IDE_STATUS_READY)){ + udata.u_error = EIO; + return -1; + } + } + + return 0; +} + /****************************************************************************/ /* Code below this point used only once, at startup, so we want it to live */ /* in the DISCARD segment. sdcc only allows us to specify one segment for */ @@ -152,7 +181,6 @@ static void devide_init_drive(uint8_t drive) { blkdev_t *blk; uint8_t *buffer, select; - uint32_t size; switch(drive){ case 0: select = 0xE0; break; @@ -160,6 +188,8 @@ static void devide_init_drive(uint8_t drive) default: return; } + drive_flags[drive] = 0; + kprintf("IDE drive %d: ", drive); /* Reset depends upon the presence of alt control, which is optional */ @@ -203,19 +233,31 @@ static void devide_init_drive(uint8_t drive) goto failout; } + if( !(((uint16_t*)buffer)[82] == 0x0000 && ((uint16_t*)buffer)[83] == 0x0000) || + (((uint16_t*)buffer)[82] == 0xFFFF && ((uint16_t*)buffer)[83] == 0xFFFF) ){ + /* command set notification is supported */ + if(buffer[164] & 0x20){ + /* write cache is supported */ + drive_flags[drive] |= FLAG_WRITE_CACHE; + } + } + + blk = blkdev_alloc(); + if(!blk) + goto failout; + + blk->transfer = devide_transfer_sector; + blk->flush = devide_flush_cache; + blk->drive_number = drive; + /* read out the drive's sector count */ - size = le32_to_cpu(*((uint32_t*)&buffer[120])); + blk->drive_lba_count = le32_to_cpu(*((uint32_t*)&buffer[120])); /* done with our temporary memory */ brelse((bufptr)buffer); - blk = blkdev_alloc(); - if (blk) { - blk->transfer = devide_transfer_sector; - blk->drive_number = drive; - blk->drive_lba_count = size; - blkdev_scan(blk, SWAPSCAN); - } + /* scan partitions */ + blkdev_scan(blk, SWAPSCAN); return; failout: diff --git a/Kernel/dev/devide.h b/Kernel/dev/devide.h index 560cb93d..2129bca3 100644 --- a/Kernel/dev/devide.h +++ b/Kernel/dev/devide.h @@ -64,6 +64,7 @@ void devide_init(void); /* IDE command codes */ #define IDE_CMD_READ_SECTOR 0x20 #define IDE_CMD_WRITE_SECTOR 0x30 +#define IDE_CMD_FLUSH_CACHE 0xE7 #define IDE_CMD_IDENTIFY 0xEC #define IDE_CMD_SET_FEATURES 0xEF