mtd/drivers/mtd rfd_ftl.c,1.3,1.4
sean at infradead.org
sean at infradead.org
Sun Jul 31 18:49:17 EDT 2005
Update of /home/cvs/mtd/drivers/mtd
In directory phoenix.infradead.org:/tmp/cvs-serv28980
Modified Files:
rfd_ftl.c
Log Message:
Minor optimisation and cleanup
Index: rfd_ftl.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/rfd_ftl.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- rfd_ftl.c 26 Jun 2005 22:46:12 -0000 1.3
+++ rfd_ftl.c 31 Jul 2005 22:49:14 -0000 1.4
@@ -21,6 +21,8 @@
#include <asm/types.h>
+#define const_cpu_to_le16 __constant_cpu_to_le16
+
static int block_size = 0;
module_param(block_size, int, 0);
MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size");
@@ -52,6 +54,8 @@
#define SECTOR_SIZE 512
+#define SECTORS_PER_TRACK 63
+
struct block {
enum {
BLOCK_OK,
@@ -79,6 +83,8 @@
u16 *header_cache; /* cached header */
int is_reclaiming;
+ int cylinders;
+ int errors;
u_long *sector_map;
struct block *blocks;
};
@@ -129,6 +135,7 @@
printk(KERN_NOTICE PREFIX
"'%s': more than one entry for sector %d\n",
part->mbd.mtd->name, entry);
+ part->errors = 1;
continue;
}
@@ -159,15 +166,20 @@
/* each erase block has three bytes header, followed by the map */
part->header_sectors_per_block =
- ((HEADER_MAP_OFFSET + sectors_per_block) *
- sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE;
+ ((HEADER_MAP_OFFSET + sectors_per_block) *
+ sizeof(u16) + SECTOR_SIZE - 1) / SECTOR_SIZE;
+
part->data_sectors_per_block = sectors_per_block -
- part->header_sectors_per_block;
+ part->header_sectors_per_block;
part->header_size = (HEADER_MAP_OFFSET +
- part->data_sectors_per_block) * sizeof(u16);
- part->sector_count = part->data_sectors_per_block *
- (part->total_blocks - 1);
+ part->data_sectors_per_block) * sizeof(u16);
+
+ part->cylinders = (part->data_sectors_per_block *
+ (part->total_blocks - 1) - 1) / SECTORS_PER_TRACK;
+
+ part->sector_count = part->cylinders * SECTORS_PER_TRACK;
+
part->current_block = -1;
part->reserved_block = -1;
part->is_reclaiming = 0;
@@ -191,7 +203,7 @@
for (i=0; i<part->sector_count; i++)
part->sector_map[i] = -1;
- for (i=0, blocks_found= 0; i<part->total_blocks; i++) {
+ for (i=0, blocks_found=0; i<part->total_blocks; i++) {
rc = part->mbd.mtd->read(part->mbd.mtd,
i * part->block_size, part->header_size,
&retlen, (u_char*)part->header_cache);
@@ -207,12 +219,19 @@
}
if (blocks_found == 0) {
- printk(KERN_NOTICE PREFIX "no RFD magic found in '%s'.\n",
+ printk(KERN_NOTICE PREFIX "no RFD magic found in '%s'\n",
part->mbd.mtd->name);
rc = -ENOENT;
goto err;
}
-
+
+ if (part->reserved_block == -1) {
+ printk(KERN_NOTICE PREFIX "'%s': no empty erase unit found\n",
+ part->mbd.mtd->name);
+
+ part->errors = 1;
+ }
+
return 0;
err:
@@ -225,7 +244,7 @@
static int rfd_ftl_readsect(struct mtd_blktrans_dev *dev, u_long sector, char *buf)
{
- struct partition *part= (struct partition*)dev;
+ struct partition *part = (struct partition*)dev;
u_long addr;
size_t retlen;
int rc;
@@ -254,24 +273,20 @@
static void erase_callback(struct erase_info *erase)
{
struct partition *part;
- int i;
+ u16 magic;
+ int i, rc;
+ size_t retlen;
part = (struct partition*)erase->priv;
i = erase->addr / part->block_size;
if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) {
- printk(KERN_ERR PREFIX "internal error: erase callback "
- "for unknown offset %x on '%s'\n",
- erase->addr, part->mbd.mtd->name);
+ printk(KERN_ERR PREFIX "erase callback for unknown offset %x "
+ "on '%s'\n", erase->addr, part->mbd.mtd->name);
return;
}
- if (erase->state == MTD_ERASE_DONE) {
- part->blocks[i].state = BLOCK_ERASED;
- part->blocks[i].free_sectors = part->data_sectors_per_block;
- part->blocks[i].used_sectors = 0;
- part->blocks[i].erases++;
- } else {
+ if (erase->state != MTD_ERASE_DONE) {
printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', "
"state %d\n", erase->addr,
part->mbd.mtd->name, erase->state);
@@ -279,8 +294,36 @@
part->blocks[i].state = BLOCK_FAILED;
part->blocks[i].free_sectors = 0;
part->blocks[i].used_sectors = 0;
+
+ kfree(erase);
+
+ return;
}
+ magic = const_cpu_to_le16(RFD_MAGIC);
+
+ part->blocks[i].state = BLOCK_ERASED;
+ part->blocks[i].free_sectors = part->data_sectors_per_block;
+ part->blocks[i].used_sectors = 0;
+ part->blocks[i].erases++;
+
+ rc = part->mbd.mtd->write(part->mbd.mtd,
+ part->blocks[i].offset, sizeof(magic), &retlen,
+ (u_char*)&magic);
+
+ if (!rc && retlen != sizeof(magic))
+ rc = -EIO;
+
+ if (rc) {
+ printk(KERN_NOTICE PREFIX "'%s': unable to write RFD "
+ "header at 0x%lx\n",
+ part->mbd.mtd->name,
+ part->blocks[i].offset);
+ part->blocks[i].state = BLOCK_FAILED;
+ }
+ else
+ part->blocks[i].state = BLOCK_OK;
+
kfree(erase);
}
@@ -404,7 +447,7 @@
return rc;
}
-static int reclaim_block (struct partition *part, u_long *old_sector)
+static int reclaim_block(struct partition *part, u_long *old_sector)
{
int block, best_block, score, old_sector_block;
int rc;
@@ -472,7 +515,12 @@
return rc;
}
-static int find_free_block (struct partition *part)
+/*
+ * IMPROVE: It would be best to choose the block with the most deleted sectors,
+ * because if we fill that one up first it'll have the most chance of having
+ * the least live sectors at reclaim.
+ */
+static int find_free_block(const struct partition *part)
{
int block, stop;
@@ -493,7 +541,7 @@
return -1;
}
-static int find_writeable_block (struct partition *part, u_long *old_sector)
+static int find_writeable_block(struct partition *part, u_long *old_sector)
{
int rc, block;
size_t retlen;
@@ -515,29 +563,8 @@
}
}
- if (part->blocks[block].state == BLOCK_ERASED) {
- u16 magic = cpu_to_le16(RFD_MAGIC);
-
- rc = part->mbd.mtd->write(part->mbd.mtd,
- part->blocks[block].offset, sizeof(magic), &retlen,
- (u_char*)&magic);
-
- if (!rc && retlen != sizeof(magic))
- rc = -EIO;
-
- if (rc) {
- printk(KERN_NOTICE PREFIX "'%s': unable to write RFD "
- "header at 0x%lx\n",
- part->mbd.mtd->name,
- part->blocks[block].offset);
- goto err;
- }
- part->blocks[block].state = BLOCK_OK;
- }
-
- rc = part->mbd.mtd->read(part->mbd.mtd,
- part->blocks[block].offset, part->header_size,
- &retlen, (u_char*)part->header_cache);
+ rc = part->mbd.mtd->read(part->mbd.mtd, part->blocks[block].offset,
+ part->header_size, &retlen, (u_char*)part->header_cache);
if (!rc && retlen != part->header_size)
rc = -EIO;
@@ -555,12 +582,12 @@
return rc;
}
-static int mark_sector_removed(struct partition *part, u_long old_addr)
+static int mark_sector_deleted(struct partition *part, u_long old_addr)
{
int block, offset, rc;
u_long addr;
size_t retlen;
- u16 del = cpu_to_le16(SECTOR_DELETED);
+ u16 del = const_cpu_to_le16(SECTOR_DELETED);
block = old_addr / part->block_size;
offset = (old_addr % part->block_size) / SECTOR_SIZE -
@@ -593,9 +620,29 @@
return rc;
}
+static int find_free_sector(const struct partition *part, const struct block *block)
+{
+ int i, stop;
+
+ i = stop = part->data_sectors_per_block - block->free_sectors;
+
+ do {
+ if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i])
+ == SECTOR_FREE)
+ return i;
+
+ if (++i == part->data_sectors_per_block)
+ i = 0;
+ }
+ while(i != stop);
+
+ return -1;
+}
+
static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf, ulong *old_addr)
{
- struct partition *part= (struct partition*)dev;
+ struct partition *part = (struct partition*)dev;
+ struct block *block;
u_long addr;
int i;
int rc;
@@ -610,15 +657,17 @@
goto err;
}
- for (i=0; i<part->data_sectors_per_block; i++) {
- if (le16_to_cpu(part->header_cache[HEADER_MAP_OFFSET + i])
- == SECTOR_FREE)
- break;
- }
- BUG_ON(part->data_sectors_per_block == i);
+ block = &part->blocks[part->current_block];
+
+ i = find_free_sector(part, block);
+ if (i < 0) {
+ rc = -ENOSPC;
+ goto err;
+ }
+
addr = (i + part->header_sectors_per_block) * SECTOR_SIZE +
- part->blocks[part->current_block].offset;
+ block->offset;
rc = part->mbd.mtd->write(part->mbd.mtd,
addr, SECTOR_SIZE, &retlen, (u_char*)buf);
@@ -638,8 +687,7 @@
part->header_cache[i + HEADER_MAP_OFFSET] = entry;
- addr = part->blocks[part->current_block].offset +
- (HEADER_MAP_OFFSET + i) * sizeof(u16);
+ addr = block->offset + (HEADER_MAP_OFFSET + i) * sizeof(u16);
rc = part->mbd.mtd->write(part->mbd.mtd, addr,
sizeof(entry), &retlen, (u_char*)&entry);
@@ -652,8 +700,8 @@
if (rc)
goto err;
}
- part->blocks[part->current_block].used_sectors++;
- part->blocks[part->current_block].free_sectors--;
+ block->used_sectors++;
+ block->free_sectors--;
err:
return rc;
@@ -661,7 +709,7 @@
static int rfd_ftl_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf)
{
- struct partition *part= (struct partition*)dev;
+ struct partition *part = (struct partition*)dev;
u_long old_addr;
int i;
int rc = 0;
@@ -694,7 +742,7 @@
part->sector_map[sector] = -1;
if (old_addr != -1)
- rc = mark_sector_removed(part, old_addr);
+ rc = mark_sector_deleted(part, old_addr);
err:
return rc;
@@ -705,8 +753,8 @@
struct partition *part = (struct partition*)dev;
geo->heads = 1;
- geo->sectors = part->data_sectors_per_block;
- geo->cylinders = part->total_blocks - 1;
+ geo->sectors = SECTORS_PER_TRACK;
+ geo->cylinders = part->cylinders;
return 0;
}
@@ -715,7 +763,7 @@
{
struct partition *part;
- if(mtd->type != MTD_NORFLASH)
+ if (mtd->type != MTD_NORFLASH)
return;
part = kcalloc(1, sizeof(struct partition), GFP_KERNEL);
@@ -742,11 +790,9 @@
part->mbd.devnum = -1;
if (!(mtd->flags & MTD_WRITEABLE))
part->mbd.readonly = 1;
- else if (part->reserved_block == -1) {
- printk(KERN_NOTICE PREFIX "'%s': no empty erase unit "
- "found, setting read-only\n",
- part->mbd.mtd->name);
-
+ else if (part->errors) {
+ printk(KERN_NOTICE PREFIX "'%s': errors found, "
+ "setting read-only", mtd->name);
part->mbd.readonly = 1;
}
More information about the linux-mtd-cvs
mailing list