#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/console.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/mtd/mtd.h>
#include <linux/kmsg_dump.h>
#define MTDOOPS_MAX_MTD_SIZE (8 * 1024 * 1024)
#define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
#define MTDOOPS_HEADER_SIZE 8
static unsigned long record_size = 4096;
module_param(record_size, ulong, 0400);
MODULE_PARM_DESC(record_size,
"record size for MTD OOPS pages in bytes (default 4096)");
module_param_string(mtddev, mtddev, 80, 0400);
"name or index number of the MTD device to use");
static int dump_oops = 1;
module_param(dump_oops, int, 0600);
MODULE_PARM_DESC(dump_oops,
"set to 1 to dump oopses, 0 to only dump panics (default 1)");
static struct mtdoops_context {
struct work_struct work_erase;
struct work_struct work_write;
unsigned long *oops_page_used;
static void mark_page_used(struct mtdoops_context *cxt, int page)
set_bit(page, cxt->oops_page_used);
static void mark_page_unused(struct mtdoops_context *cxt, int page)
clear_bit(page, cxt->oops_page_used);
static int page_is_used(struct mtdoops_context *cxt, int page)
return test_bit(page, cxt->oops_page_used);
static int mtdoops_erase_block(struct mtdoops_context *cxt, int offset)
struct mtd_info *mtd = cxt->mtd;
u32 start_page_offset = mtd_div_by_eb(offset, mtd) * mtd->erasesize;
u32 start_page = start_page_offset / record_size;
u32 erase_pages = mtd->erasesize / record_size;
erase.len = mtd->erasesize;
ret = mtd_erase(mtd, &erase);
printk(KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] on \"%s\" failed\n",
(unsigned long long)erase.addr,
(unsigned long long)erase.len, mtddev);