diff options
| author | Simon Kagstrom <simon.kagstrom@netinsight.net> | 2009-10-29 08:41:19 -0400 |
|---|---|---|
| committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-11-30 07:02:05 -0500 |
| commit | 9507b0c838e37651030d453b9cf3b136cfeefe89 (patch) | |
| tree | 113594832dea4e3706db630725026b788d202eda /drivers/mtd | |
| parent | 1114e3d00f539ecb7a8415663f2a47a80e00a537 (diff) | |
mtd: mtdoops: make record size configurable
The main justification for this is to allow catching long messages
during a panic, where the top part might otherwise be lost since moving
to the next block can require a flash erase.
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Reviewed-by: Anders Grafstrom <anders.grafstrom@netinsight.net>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
| -rw-r--r-- | drivers/mtd/mtdoops.c | 74 |
1 files changed, 43 insertions, 31 deletions
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index b016eee18657..64772dc0ea2b 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c | |||
| @@ -37,7 +37,11 @@ | |||
| 37 | #define MTDOOPS_MAX_MTD_SIZE (8 * 1024 * 1024) | 37 | #define MTDOOPS_MAX_MTD_SIZE (8 * 1024 * 1024) |
| 38 | 38 | ||
| 39 | #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00 | 39 | #define MTDOOPS_KERNMSG_MAGIC 0x5d005d00 |
| 40 | #define OOPS_PAGE_SIZE 4096 | 40 | |
| 41 | static unsigned long record_size = 4096; | ||
| 42 | module_param(record_size, ulong, 0400); | ||
| 43 | MODULE_PARM_DESC(record_size, | ||
| 44 | "record size for MTD OOPS pages in bytes (default 4096)"); | ||
| 41 | 45 | ||
| 42 | static struct mtdoops_context { | 46 | static struct mtdoops_context { |
| 43 | int mtd_index; | 47 | int mtd_index; |
| @@ -83,8 +87,8 @@ static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset) | |||
| 83 | { | 87 | { |
| 84 | struct mtd_info *mtd = cxt->mtd; | 88 | struct mtd_info *mtd = cxt->mtd; |
| 85 | u32 start_page_offset = mtd_div_by_eb(offset, mtd) * mtd->erasesize; | 89 | u32 start_page_offset = mtd_div_by_eb(offset, mtd) * mtd->erasesize; |
| 86 | u32 start_page = start_page_offset / OOPS_PAGE_SIZE; | 90 | u32 start_page = start_page_offset / record_size; |
| 87 | u32 erase_pages = mtd->erasesize / OOPS_PAGE_SIZE; | 91 | u32 erase_pages = mtd->erasesize / record_size; |
| 88 | struct erase_info erase; | 92 | struct erase_info erase; |
| 89 | DECLARE_WAITQUEUE(wait, current); | 93 | DECLARE_WAITQUEUE(wait, current); |
| 90 | wait_queue_head_t wait_q; | 94 | wait_queue_head_t wait_q; |
| @@ -152,15 +156,15 @@ static void mtdoops_workfunc_erase(struct work_struct *work) | |||
| 152 | if (!mtd) | 156 | if (!mtd) |
| 153 | return; | 157 | return; |
| 154 | 158 | ||
| 155 | mod = (cxt->nextpage * OOPS_PAGE_SIZE) % mtd->erasesize; | 159 | mod = (cxt->nextpage * record_size) % mtd->erasesize; |
| 156 | if (mod != 0) { | 160 | if (mod != 0) { |
| 157 | cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / OOPS_PAGE_SIZE); | 161 | cxt->nextpage = cxt->nextpage + ((mtd->erasesize - mod) / record_size); |
| 158 | if (cxt->nextpage >= cxt->oops_pages) | 162 | if (cxt->nextpage >= cxt->oops_pages) |
| 159 | cxt->nextpage = 0; | 163 | cxt->nextpage = 0; |
| 160 | } | 164 | } |
| 161 | 165 | ||
| 162 | while (mtd->block_isbad) { | 166 | while (mtd->block_isbad) { |
| 163 | ret = mtd->block_isbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE); | 167 | ret = mtd->block_isbad(mtd, cxt->nextpage * record_size); |
| 164 | if (!ret) | 168 | if (!ret) |
| 165 | break; | 169 | break; |
| 166 | if (ret < 0) { | 170 | if (ret < 0) { |
| @@ -168,20 +172,20 @@ static void mtdoops_workfunc_erase(struct work_struct *work) | |||
| 168 | return; | 172 | return; |
| 169 | } | 173 | } |
| 170 | badblock: | 174 | badblock: |
| 171 | printk(KERN_WARNING "mtdoops: bad block at %08x\n", | 175 | printk(KERN_WARNING "mtdoops: bad block at %08lx\n", |
| 172 | cxt->nextpage * OOPS_PAGE_SIZE); | 176 | cxt->nextpage * record_size); |
| 173 | i++; | 177 | i++; |
| 174 | cxt->nextpage = cxt->nextpage + (mtd->erasesize / OOPS_PAGE_SIZE); | 178 | cxt->nextpage = cxt->nextpage + (mtd->erasesize / record_size); |
| 175 | if (cxt->nextpage >= cxt->oops_pages) | 179 | if (cxt->nextpage >= cxt->oops_pages) |
| 176 | cxt->nextpage = 0; | 180 | cxt->nextpage = 0; |
| 177 | if (i == cxt->oops_pages / (mtd->erasesize / OOPS_PAGE_SIZE)) { | 181 | if (i == cxt->oops_pages / (mtd->erasesize / record_size)) { |
| 178 | printk(KERN_ERR "mtdoops: all blocks bad!\n"); | 182 | printk(KERN_ERR "mtdoops: all blocks bad!\n"); |
| 179 | return; | 183 | return; |
| 180 | } | 184 | } |
| 181 | } | 185 | } |
| 182 | 186 | ||
| 183 | for (j = 0, ret = -1; (j < 3) && (ret < 0); j++) | 187 | for (j = 0, ret = -1; (j < 3) && (ret < 0); j++) |
| 184 | ret = mtdoops_erase_block(cxt, cxt->nextpage * OOPS_PAGE_SIZE); | 188 | ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size); |
| 185 | 189 | ||
| 186 | if (ret >= 0) { | 190 | if (ret >= 0) { |
| 187 | printk(KERN_DEBUG "mtdoops: ready %d, %d\n", | 191 | printk(KERN_DEBUG "mtdoops: ready %d, %d\n", |
| @@ -191,7 +195,7 @@ badblock: | |||
| 191 | } | 195 | } |
| 192 | 196 | ||
| 193 | if (mtd->block_markbad && ret == -EIO) { | 197 | if (mtd->block_markbad && ret == -EIO) { |
| 194 | ret = mtd->block_markbad(mtd, cxt->nextpage * OOPS_PAGE_SIZE); | 198 | ret = mtd->block_markbad(mtd, cxt->nextpage * record_size); |
| 195 | if (ret < 0) { | 199 | if (ret < 0) { |
| 196 | printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n"); | 200 | printk(KERN_ERR "mtdoops: block_markbad failed, aborting\n"); |
| 197 | return; | 201 | return; |
| @@ -206,22 +210,22 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic) | |||
| 206 | size_t retlen; | 210 | size_t retlen; |
| 207 | int ret; | 211 | int ret; |
| 208 | 212 | ||
| 209 | if (cxt->writecount < OOPS_PAGE_SIZE) | 213 | if (cxt->writecount < record_size) |
| 210 | memset(cxt->oops_buf + cxt->writecount, 0xff, | 214 | memset(cxt->oops_buf + cxt->writecount, 0xff, |
| 211 | OOPS_PAGE_SIZE - cxt->writecount); | 215 | record_size - cxt->writecount); |
| 212 | 216 | ||
| 213 | if (panic) | 217 | if (panic) |
| 214 | ret = mtd->panic_write(mtd, cxt->nextpage * OOPS_PAGE_SIZE, | 218 | ret = mtd->panic_write(mtd, cxt->nextpage * record_size, |
| 215 | OOPS_PAGE_SIZE, &retlen, cxt->oops_buf); | 219 | record_size, &retlen, cxt->oops_buf); |
| 216 | else | 220 | else |
| 217 | ret = mtd->write(mtd, cxt->nextpage * OOPS_PAGE_SIZE, | 221 | ret = mtd->write(mtd, cxt->nextpage * record_size, |
| 218 | OOPS_PAGE_SIZE, &retlen, cxt->oops_buf); | 222 | record_size, &retlen, cxt->oops_buf); |
| 219 | 223 | ||
| 220 | cxt->writecount = 0; | 224 | cxt->writecount = 0; |
| 221 | 225 | ||
| 222 | if (retlen != OOPS_PAGE_SIZE || ret < 0) | 226 | if (retlen != record_size || ret < 0) |
| 223 | printk(KERN_ERR "mtdoops: write failure at %d (%td of %d written), error %d\n", | 227 | printk(KERN_ERR "mtdoops: write failure at %ld (%td of %ld written), error %d\n", |
| 224 | cxt->nextpage * OOPS_PAGE_SIZE, retlen, OOPS_PAGE_SIZE, ret); | 228 | cxt->nextpage * record_size, retlen, record_size, ret); |
| 225 | mark_page_used(cxt, cxt->nextpage); | 229 | mark_page_used(cxt, cxt->nextpage); |
| 226 | 230 | ||
| 227 | mtdoops_inc_counter(cxt); | 231 | mtdoops_inc_counter(cxt); |
| @@ -246,10 +250,10 @@ static void find_next_position(struct mtdoops_context *cxt) | |||
| 246 | for (page = 0; page < cxt->oops_pages; page++) { | 250 | for (page = 0; page < cxt->oops_pages; page++) { |
| 247 | /* Assume the page is used */ | 251 | /* Assume the page is used */ |
| 248 | mark_page_used(cxt, page); | 252 | mark_page_used(cxt, page); |
| 249 | ret = mtd->read(mtd, page * OOPS_PAGE_SIZE, 8, &retlen, (u_char *) &count[0]); | 253 | ret = mtd->read(mtd, page * record_size, 8, &retlen, (u_char *) &count[0]); |
| 250 | if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) { | 254 | if (retlen != 8 || (ret < 0 && ret != -EUCLEAN)) { |
| 251 | printk(KERN_ERR "mtdoops: read failure at %d (%td of 8 read), err %d\n", | 255 | printk(KERN_ERR "mtdoops: read failure at %ld (%td of 8 read), err %d\n", |
| 252 | page * OOPS_PAGE_SIZE, retlen, ret); | 256 | page * record_size, retlen, ret); |
| 253 | continue; | 257 | continue; |
| 254 | } | 258 | } |
| 255 | 259 | ||
| @@ -293,7 +297,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) | |||
| 293 | struct mtdoops_context *cxt = &oops_cxt; | 297 | struct mtdoops_context *cxt = &oops_cxt; |
| 294 | u64 mtdoops_pages = mtd->size; | 298 | u64 mtdoops_pages = mtd->size; |
| 295 | 299 | ||
| 296 | do_div(mtdoops_pages, OOPS_PAGE_SIZE); | 300 | do_div(mtdoops_pages, record_size); |
| 297 | 301 | ||
| 298 | if (cxt->name && !strcmp(mtd->name, cxt->name)) | 302 | if (cxt->name && !strcmp(mtd->name, cxt->name)) |
| 299 | cxt->mtd_index = mtd->index; | 303 | cxt->mtd_index = mtd->index; |
| @@ -307,7 +311,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) | |||
| 307 | return; | 311 | return; |
| 308 | } | 312 | } |
| 309 | 313 | ||
| 310 | if (mtd->erasesize < OOPS_PAGE_SIZE) { | 314 | if (mtd->erasesize < record_size) { |
| 311 | printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n", | 315 | printk(KERN_ERR "mtdoops: eraseblock size of MTD partition %d too small\n", |
| 312 | mtd->index); | 316 | mtd->index); |
| 313 | return; | 317 | return; |
| @@ -328,7 +332,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) | |||
| 328 | } | 332 | } |
| 329 | 333 | ||
| 330 | cxt->mtd = mtd; | 334 | cxt->mtd = mtd; |
| 331 | cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE; | 335 | cxt->oops_pages = (int)mtd->size / record_size; |
| 332 | find_next_position(cxt); | 336 | find_next_position(cxt); |
| 333 | printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index); | 337 | printk(KERN_INFO "mtdoops: Attached to MTD device %d\n", mtd->index); |
| 334 | } | 338 | } |
| @@ -403,15 +407,15 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count) | |||
| 403 | cxt->writecount = 8; | 407 | cxt->writecount = 8; |
| 404 | } | 408 | } |
| 405 | 409 | ||
| 406 | if (count + cxt->writecount > OOPS_PAGE_SIZE) | 410 | if (count + cxt->writecount > record_size) |
| 407 | count = OOPS_PAGE_SIZE - cxt->writecount; | 411 | count = record_size - cxt->writecount; |
| 408 | 412 | ||
| 409 | memcpy(cxt->oops_buf + cxt->writecount, s, count); | 413 | memcpy(cxt->oops_buf + cxt->writecount, s, count); |
| 410 | cxt->writecount += count; | 414 | cxt->writecount += count; |
| 411 | 415 | ||
| 412 | spin_unlock_irqrestore(&cxt->writecount_lock, flags); | 416 | spin_unlock_irqrestore(&cxt->writecount_lock, flags); |
| 413 | 417 | ||
| 414 | if (cxt->writecount == OOPS_PAGE_SIZE) | 418 | if (cxt->writecount == record_size) |
| 415 | mtdoops_console_sync(); | 419 | mtdoops_console_sync(); |
| 416 | } | 420 | } |
| 417 | 421 | ||
| @@ -450,8 +454,16 @@ static int __init mtdoops_console_init(void) | |||
| 450 | { | 454 | { |
| 451 | struct mtdoops_context *cxt = &oops_cxt; | 455 | struct mtdoops_context *cxt = &oops_cxt; |
| 452 | 456 | ||
| 457 | if ((record_size & 4095) != 0) { | ||
| 458 | printk(KERN_ERR "mtdoops: record_size must be a multiple of 4096\n"); | ||
| 459 | return -EINVAL; | ||
| 460 | } | ||
| 461 | if (record_size < 4096) { | ||
| 462 | printk(KERN_ERR "mtdoops: record_size must be over 4096 bytes\n"); | ||
| 463 | return -EINVAL; | ||
| 464 | } | ||
| 453 | cxt->mtd_index = -1; | 465 | cxt->mtd_index = -1; |
| 454 | cxt->oops_buf = vmalloc(OOPS_PAGE_SIZE); | 466 | cxt->oops_buf = vmalloc(record_size); |
| 455 | if (!cxt->oops_buf) { | 467 | if (!cxt->oops_buf) { |
| 456 | printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n"); | 468 | printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n"); |
| 457 | return -ENOMEM; | 469 | return -ENOMEM; |
