Import xiaomi mtd changes from mayfly-s-oss
This commit is contained in:
parent
be89c2c54e
commit
ced9995b90
@ -18,6 +18,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/sched/debug.h>
|
||||
|
||||
#define PON_REV2 0x01
|
||||
|
||||
@ -51,6 +53,11 @@
|
||||
#define PON_DBC_CTL 0x71
|
||||
#define PON_DBC_DELAY_MASK 0x7
|
||||
|
||||
#if IS_ENABLED(CONFIG_MTD_OOPS)
|
||||
extern int g_long_press_reason;
|
||||
extern void mtdoops_do_dump_if(int reason);
|
||||
#endif
|
||||
|
||||
struct pm8941_data {
|
||||
unsigned int pull_up_bit;
|
||||
unsigned int status_bit;
|
||||
@ -141,6 +148,35 @@ static int pm8941_reboot_notify(struct notifier_block *nb,
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
|
||||
void show_state_filter_single(unsigned long state_filter)
|
||||
{
|
||||
struct task_struct *g, *p;
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
printk(KERN_INFO
|
||||
" task PC stack pid father\n");
|
||||
#else
|
||||
printk(KERN_INFO
|
||||
" task PC stack pid father\n");
|
||||
#endif
|
||||
rcu_read_lock();
|
||||
for_each_process_thread(g, p) {
|
||||
/*
|
||||
* reset the NMI-timeout, listing all files on a slow
|
||||
* console might take a lot of time:
|
||||
* Also, reset softlockup watchdogs on all CPUs, because
|
||||
* another CPU might be blocked waiting for us to process
|
||||
* an IPI.
|
||||
*/
|
||||
touch_nmi_watchdog();
|
||||
//touch_all_softlockup_watchdogs();
|
||||
if (p->state == state_filter)
|
||||
sched_show_task(p);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
|
||||
{
|
||||
struct pm8941_pwrkey *pwrkey = _data;
|
||||
@ -148,6 +184,42 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
|
||||
int error;
|
||||
u64 elapsed_us;
|
||||
|
||||
if (!strcmp(pwrkey->data->name,"pmic_pwrkey_bark")){
|
||||
|
||||
#if IS_ENABLED(CONFIG_MTD_OOPS)
|
||||
error = regmap_read(pwrkey->regmap,
|
||||
pwrkey->baseaddr + PON_RT_STS, &sts);
|
||||
if (error)
|
||||
return IRQ_HANDLED;
|
||||
sts &= pwrkey->data->status_bit;
|
||||
if(sts){
|
||||
dev_err(pwrkey->dev, "pwrkey_bark_irq trigger, start dump mtdoops");
|
||||
mtdoops_do_dump_if(g_long_press_reason);
|
||||
}
|
||||
#endif
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
else if (!strcmp(pwrkey->data->name,"pmic_pwrkey_resin_bark")){
|
||||
|
||||
error = regmap_read(pwrkey->regmap,
|
||||
pwrkey->baseaddr + PON_RT_STS, &sts);
|
||||
if (error)
|
||||
return IRQ_HANDLED;
|
||||
sts &= pwrkey->data->status_bit;
|
||||
if(sts){
|
||||
int tmp_console = console_loglevel;
|
||||
dev_err(pwrkey->dev, "pwrkey_resin_bark_irq trigger, start D&R task info");
|
||||
console_verbose();
|
||||
pr_info("------ collect D&R-state processes info before long comb key ------\n");
|
||||
show_state_filter_single(TASK_UNINTERRUPTIBLE);
|
||||
show_state_filter_single(TASK_RUNNING);
|
||||
pr_info("------ end collecting D&R-state processes info ------\n");
|
||||
console_loglevel = tmp_console;
|
||||
}
|
||||
else{
|
||||
}
|
||||
}
|
||||
|
||||
if (pwrkey->sw_debounce_time_us) {
|
||||
elapsed_us = ktime_us_delta(ktime_get(),
|
||||
pwrkey->last_release_time);
|
||||
@ -471,11 +543,33 @@ static const struct pm8941_data pon_gen3_resin_data = {
|
||||
.has_pon_pbs = true,
|
||||
};
|
||||
|
||||
static const struct pm8941_data pon_gen3_pwrkey_bark_data = {
|
||||
.status_bit = PON_GEN3_KPDPWR_N_SET,
|
||||
.name = "pmic_pwrkey_bark",
|
||||
.phys = "pmic_pwrkey_bark/input0",
|
||||
.supports_ps_hold_poff_config = false,
|
||||
.supports_debounce_config = false,
|
||||
.needs_sw_debounce = true,
|
||||
.has_pon_pbs = true,
|
||||
};
|
||||
|
||||
static const struct pm8941_data pon_gen3_pwrkey_resin_bark_data = {
|
||||
.status_bit = PON_GEN3_KPDPWR_N_SET,
|
||||
.name = "pmic_pwrkey_resin_bark",
|
||||
.phys = "pmic_pwrkey_resin_bark/input0",
|
||||
.supports_ps_hold_poff_config = false,
|
||||
.supports_debounce_config = false,
|
||||
.needs_sw_debounce = true,
|
||||
.has_pon_pbs = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id pm8941_pwr_key_id_table[] = {
|
||||
{ .compatible = "qcom,pm8941-pwrkey", .data = &pwrkey_data },
|
||||
{ .compatible = "qcom,pm8941-resin", .data = &resin_data },
|
||||
{ .compatible = "qcom,pmk8350-pwrkey", .data = &pon_gen3_pwrkey_data },
|
||||
{ .compatible = "qcom,pmk8350-resin", .data = &pon_gen3_resin_data },
|
||||
{ .compatible = "qcom,pmk8350-pwrkey-bark", .data = &pon_gen3_pwrkey_bark_data },
|
||||
{ .compatible = "qcom,pmk8350-pwrkey-resin-bark", .data = &pon_gen3_pwrkey_resin_bark_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table);
|
||||
|
@ -141,6 +141,7 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
|
||||
int offset = to & ~PAGE_MASK; // page offset
|
||||
int cpylen;
|
||||
|
||||
printk(KERN_ERR "_block2mtd_write: start len = %d, mapping_index= %d \n",len,index);
|
||||
while (len) {
|
||||
if ((offset+len) > PAGE_SIZE)
|
||||
cpylen = PAGE_SIZE - offset; // multiple pages
|
||||
@ -168,6 +169,8 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
|
||||
offset = 0;
|
||||
index++;
|
||||
}
|
||||
|
||||
printk(KERN_ERR "_block2mtd_write: finish all \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -183,6 +186,7 @@ static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
mutex_unlock(&dev->write_mutex);
|
||||
if (err > 0)
|
||||
err = 0;
|
||||
dev->mtd._sync(mtd);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -213,16 +217,34 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
|
||||
}
|
||||
|
||||
|
||||
int delSubStr(char * src, char * sub,char * result)
|
||||
{
|
||||
int i,find = 0;
|
||||
int len_src = strlen(src);
|
||||
int len_sub = strlen(sub);
|
||||
for( i = 0 ; i <= len_src - len_sub; i++){
|
||||
if(strncmp(src+i, sub, len_sub)==0){
|
||||
strncpy(result,src,i);
|
||||
strncpy(result+i,src+i+len_sub,len_src-i-len_sub);
|
||||
find =1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return find;
|
||||
}
|
||||
|
||||
|
||||
static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
int timeout)
|
||||
{
|
||||
#ifndef MODULE
|
||||
//#ifndef MODULE
|
||||
int i;
|
||||
#endif
|
||||
//#endif
|
||||
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
|
||||
struct block_device *bdev;
|
||||
struct block2mtd_dev *dev;
|
||||
char *name;
|
||||
char name_for_find_devt[80]={0};
|
||||
|
||||
if (!devname)
|
||||
return NULL;
|
||||
@ -234,11 +256,14 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
/* Get a handle on the device */
|
||||
bdev = blkdev_get_by_path(devname, mode, dev);
|
||||
|
||||
#ifndef MODULE
|
||||
//#ifndef MODULE
|
||||
/*
|
||||
* We might not have the root device mounted at this point.
|
||||
* Try to resolve the device name by other means.
|
||||
*/
|
||||
if(!delSubStr(devname, "block/",name_for_find_devt))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; IS_ERR(bdev) && i <= timeout; i++) {
|
||||
dev_t devt;
|
||||
|
||||
@ -251,12 +276,12 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
msleep(1000);
|
||||
wait_for_device_probe();
|
||||
|
||||
devt = name_to_dev_t(devname);
|
||||
devt = name_to_dev_t(name_for_find_devt);
|
||||
if (!devt)
|
||||
continue;
|
||||
bdev = blkdev_get_by_dev(devt, mode, dev);
|
||||
}
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
if (IS_ERR(bdev)) {
|
||||
pr_err("error: cannot open device %s\n", devname);
|
||||
@ -307,6 +332,8 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
dev->mtd.index,
|
||||
dev->mtd.name + strlen("block2mtd: "),
|
||||
dev->mtd.erasesize >> 10, dev->mtd.erasesize);
|
||||
|
||||
pr_err("block2mtd: add device sucess \n");
|
||||
return dev;
|
||||
|
||||
err_destroy_mutex:
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
@ -18,14 +19,77 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/kmsg_dump.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <generated/utsrelease.h>
|
||||
|
||||
|
||||
struct pmsg_buffer_hdr {
|
||||
uint32_t sig;
|
||||
atomic_t start;
|
||||
atomic_t size;
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
/* Maximum MTD partition size */
|
||||
#define MTDOOPS_MAX_MTD_SIZE (8 * 1024 * 1024)
|
||||
#define MTDOOPS_MAX_MTD_SIZE (16 * 1024 * 1024)
|
||||
|
||||
#define MTDOOPS_KERNMSG_MAGIC 0x5d005d00
|
||||
#define MTDOOPS_HEADER_SIZE 8
|
||||
|
||||
/* Expand kmsg_dump_reason
|
||||
enum kmsg_dump_reason {
|
||||
KMSG_DUMP_UNDEF,
|
||||
KMSG_DUMP_PANIC,
|
||||
KMSG_DUMP_OOPS,
|
||||
KMSG_DUMP_EMERG,
|
||||
KMSG_DUMP_SHUTDOWN,
|
||||
KMSG_DUMP_MAX
|
||||
};
|
||||
*/
|
||||
|
||||
enum mtd_dump_reason {
|
||||
MTD_DUMP_UNDEF,
|
||||
MTD_DUMP_PANIC,
|
||||
MTD_DUMP_OOPS,
|
||||
MTD_DUMP_EMERG,
|
||||
MTD_DUMP_SHUTDOWN,
|
||||
MTD_DUMP_RESTART,
|
||||
MTD_DUMP_POWEROFF,
|
||||
MTD_DUMP_LONG_PRESS,
|
||||
MTD_DUMP_MAX
|
||||
};
|
||||
|
||||
|
||||
static char *kdump_reason[8] = {
|
||||
"Unknown",
|
||||
"Kernel Panic",
|
||||
"Oops!",
|
||||
"Emerg",
|
||||
"Shut Down",
|
||||
"Restart",
|
||||
"PowerOff",
|
||||
"Long Press"
|
||||
};
|
||||
|
||||
|
||||
enum mtdoops_log_type {
|
||||
MTDOOPS_TYPE_UNDEF,
|
||||
MTDOOPS_TYPE_DMESG,
|
||||
MTDOOPS_TYPE_PMSG,
|
||||
};
|
||||
static char *log_type[4] = {
|
||||
"Unknown",
|
||||
"LAST KMSG",
|
||||
"LAST LOGCAT"
|
||||
};
|
||||
|
||||
int g_long_press_reason = MTD_DUMP_LONG_PRESS;
|
||||
EXPORT_SYMBOL_GPL(g_long_press_reason);
|
||||
|
||||
static unsigned long record_size = 4096;
|
||||
static unsigned long lkmsg_record_size = 512 * 1024;
|
||||
module_param(record_size, ulong, 0400);
|
||||
MODULE_PARM_DESC(record_size,
|
||||
"record size for MTD OOPS pages in bytes (default 4096)");
|
||||
@ -35,13 +99,27 @@ module_param_string(mtddev, mtddev, 80, 0400);
|
||||
MODULE_PARM_DESC(mtddev,
|
||||
"name or index number of the MTD device to use");
|
||||
|
||||
static int dump_oops = 1;
|
||||
static int dump_oops = 0;
|
||||
module_param(dump_oops, int, 0600);
|
||||
MODULE_PARM_DESC(dump_oops,
|
||||
"set to 1 to dump oopses, 0 to only dump panics (default 1)");
|
||||
|
||||
#define MAX_CMDLINE_PARAM_LEN 64
|
||||
static char build_fingerprint[MAX_CMDLINE_PARAM_LEN] = {0};
|
||||
module_param_string(fingerprint, build_fingerprint, MAX_CMDLINE_PARAM_LEN,0644);
|
||||
|
||||
|
||||
struct pmsg_platform_data {
|
||||
unsigned long mem_size;
|
||||
phys_addr_t mem_address;
|
||||
unsigned long console_size;
|
||||
unsigned long pmsg_size;
|
||||
};
|
||||
|
||||
static struct mtdoops_context {
|
||||
struct kmsg_dumper dump;
|
||||
struct notifier_block reboot_nb;
|
||||
struct pmsg_platform_data pmsg_data;
|
||||
|
||||
int mtd_index;
|
||||
struct work_struct work_erase;
|
||||
@ -107,13 +185,14 @@ static void mtdoops_inc_counter(struct mtdoops_context *cxt)
|
||||
if (cxt->nextcount == 0xffffffff)
|
||||
cxt->nextcount = 0;
|
||||
|
||||
printk(KERN_ERR "mtdoops: ready nextpage= %d, nextcount= %d (no erase), oops_page_used_flag = %lx",
|
||||
cxt->nextpage, cxt->nextcount, *cxt->oops_page_used );
|
||||
|
||||
if (page_is_used(cxt, cxt->nextpage)) {
|
||||
schedule_work(&cxt->work_erase);
|
||||
return;
|
||||
}
|
||||
|
||||
printk(KERN_DEBUG "mtdoops: ready %d, %d (no erase)\n",
|
||||
cxt->nextpage, cxt->nextcount);
|
||||
}
|
||||
|
||||
/* Scheduled work - when we can't proceed without erasing a block */
|
||||
@ -200,9 +279,10 @@ static void mtdoops_write(struct mtdoops_context *cxt, int panic)
|
||||
printk(KERN_ERR "mtdoops: write failure at %ld (%td of %ld written), error %d\n",
|
||||
cxt->nextpage * record_size, retlen, record_size, ret);
|
||||
mark_page_used(cxt, cxt->nextpage);
|
||||
memset(cxt->oops_buf, 0xff, record_size);
|
||||
|
||||
mtdoops_inc_counter(cxt);
|
||||
// device will reboot ,so do not need find next and erase
|
||||
// if (!panic)
|
||||
// mtdoops_inc_counter(cxt);
|
||||
}
|
||||
|
||||
static void mtdoops_workfunc_write(struct work_struct *work)
|
||||
@ -266,28 +346,160 @@ static void find_next_position(struct mtdoops_context *cxt)
|
||||
mtdoops_inc_counter(cxt);
|
||||
}
|
||||
|
||||
static void mtdoops_do_dump(struct kmsg_dumper *dumper,
|
||||
enum kmsg_dump_reason reason)
|
||||
static void mtdoops_add_reason(char *oops_buf, enum mtd_dump_reason reason, enum mtdoops_log_type type, int index, int nextpage)
|
||||
{
|
||||
char str_buf[200] = {0};
|
||||
int ret_len = 0;
|
||||
struct timespec64 now;
|
||||
struct tm ts;
|
||||
|
||||
ktime_get_coarse_real_ts64(&now);
|
||||
time64_to_tm(now.tv_sec, 0, &ts);
|
||||
|
||||
if (nextpage > 1)
|
||||
ret_len = snprintf(str_buf, 200,
|
||||
"\n```\n## Index: %d\t\n### Build: %s\t\n## REASON: %s\n#### LOG TYPE:%s\n#####%04ld-%02d-%02d %02d:%02d:%02d\t\n```c\t\n",
|
||||
index, build_fingerprint, kdump_reason[reason], log_type[type], ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
|
||||
else
|
||||
ret_len = snprintf(str_buf, 200,
|
||||
"\n\n## Index: %d\t\n### Build: %s\t\n## REASON: %s\n#### LOG TYPE: %s\n#####%04ld-%02d-%02d %02d:%02d:%02d\t\n```c\t\n",
|
||||
index, build_fingerprint, kdump_reason[reason], log_type[type], ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
|
||||
|
||||
memcpy(oops_buf, str_buf, ret_len);
|
||||
}
|
||||
|
||||
|
||||
static void mtdoops_add_pmsg_head(char *oops_buf, enum mtdoops_log_type type)
|
||||
{
|
||||
char str_buf[80] = {0};
|
||||
int ret_len = 0;
|
||||
struct timespec64 now;
|
||||
struct tm ts;
|
||||
|
||||
ktime_get_coarse_real_ts64(&now);
|
||||
time64_to_tm(now.tv_sec, 0, &ts);
|
||||
|
||||
ret_len = snprintf(str_buf, 80,
|
||||
"\n```\n#### LOG TYPE:%s\n#####%04ld-%02d-%02d %02d:%02d:%02d\t\n```c\t\n",
|
||||
log_type[type], ts.tm_year+1900, ts.tm_mon, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
|
||||
|
||||
memcpy(oops_buf, str_buf, ret_len);
|
||||
}
|
||||
|
||||
static void mtdoops_do_dump(struct kmsg_dumper *dumper,
|
||||
enum mtd_dump_reason reason)
|
||||
{
|
||||
static int do_dump_count = 0;
|
||||
struct mtdoops_context *cxt = container_of(dumper,
|
||||
struct mtdoops_context, dump);
|
||||
size_t ret_len = 0;
|
||||
char *pmsg_buffer_start = NULL;
|
||||
struct pmsg_buffer_hdr *p_hdr = NULL;
|
||||
int j, ret;
|
||||
|
||||
if(cxt->mtd == NULL) {
|
||||
printk(KERN_ERR "mtdoops: init is not finish. Cannot write mtd logs \n");
|
||||
return;
|
||||
}
|
||||
|
||||
do_dump_count++;
|
||||
printk(KERN_ERR "mtdoops: %s start , count = %d , page = %d, reason = %d, dump_count = %d\n",__func__,cxt->nextcount, cxt->nextpage,reason,do_dump_count);
|
||||
|
||||
if(do_dump_count>1)
|
||||
{
|
||||
for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
|
||||
ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);
|
||||
}
|
||||
|
||||
/* Only dump oopses if dump_oops is set */
|
||||
if (reason == KMSG_DUMP_OOPS && !dump_oops)
|
||||
return;
|
||||
|
||||
kmsg_dump_get_buffer(dumper, true, cxt->oops_buf + MTDOOPS_HEADER_SIZE,
|
||||
record_size - MTDOOPS_HEADER_SIZE, NULL);
|
||||
lkmsg_record_size - MTDOOPS_HEADER_SIZE, &ret_len);
|
||||
|
||||
if (reason != KMSG_DUMP_OOPS) {
|
||||
/* Panics must be written immediately */
|
||||
mtdoops_add_reason(cxt->oops_buf + MTDOOPS_HEADER_SIZE, reason, MTDOOPS_TYPE_DMESG, cxt->nextcount, cxt->nextpage);
|
||||
|
||||
pmsg_buffer_start = phys_to_virt((cxt->pmsg_data.mem_address + cxt->pmsg_data.mem_size) - cxt->pmsg_data.pmsg_size);
|
||||
p_hdr = (struct pmsg_buffer_hdr *)pmsg_buffer_start;
|
||||
|
||||
pr_err("mtdoops: mtdoops_do_dump pmsg paddr = 0x%lx \n",pmsg_buffer_start);
|
||||
|
||||
if(p_hdr->sig == 0x43474244)
|
||||
{
|
||||
void *oopsbuf = cxt->oops_buf + (MTDOOPS_HEADER_SIZE + ret_len);
|
||||
uint8_t *p_buff_end = p_hdr->data + p_hdr->size.counter;
|
||||
int pmsg_cp_size = 0;
|
||||
int pstart = p_hdr->start.counter;
|
||||
int psize = p_hdr->size.counter;
|
||||
|
||||
pmsg_cp_size = (record_size - (ret_len + MTDOOPS_HEADER_SIZE));
|
||||
if (psize <= pmsg_cp_size)
|
||||
pmsg_cp_size = psize;
|
||||
|
||||
if (pstart >= pmsg_cp_size)
|
||||
memcpy(oopsbuf, p_hdr->data, pmsg_cp_size);
|
||||
else{
|
||||
memcpy(oopsbuf, p_buff_end - (pmsg_cp_size - pstart), pmsg_cp_size - pstart);
|
||||
memcpy(oopsbuf + (pmsg_cp_size - pstart), p_hdr->data, pstart);
|
||||
}
|
||||
mtdoops_add_pmsg_head(cxt->oops_buf + (MTDOOPS_HEADER_SIZE + ret_len), MTDOOPS_TYPE_PMSG);
|
||||
}
|
||||
else
|
||||
printk(KERN_ERR "mtdoops: read pmsg failed sig = 0x%x \n", p_hdr->sig);
|
||||
|
||||
/* Panics must be written immediately */
|
||||
if (reason == KMSG_DUMP_OOPS || reason == KMSG_DUMP_PANIC) {
|
||||
mtdoops_write(cxt, 1);
|
||||
} else {
|
||||
/* For other cases, schedule work to write it "nicely" */
|
||||
schedule_work(&cxt->work_write);
|
||||
//schedule_work(&cxt->work_write);
|
||||
// we should write log immediately , if use work to write, ufs will shutdown before write log finish
|
||||
mtdoops_write(cxt, 0);
|
||||
}
|
||||
|
||||
printk(KERN_ERR "mtdoops: mtdoops_do_dump() finish \n");
|
||||
}
|
||||
|
||||
|
||||
static void mtdoops_do_dump_kmsgdump(struct kmsg_dumper *dumper,
|
||||
enum kmsg_dump_reason reason)
|
||||
{
|
||||
//mtdoops_do_dump(dumper, (enum mtd_dump_reason)reason);
|
||||
}
|
||||
|
||||
|
||||
void mtdoops_do_dump_if(int reason)
|
||||
{
|
||||
struct mtdoops_context *cxt = &oops_cxt;
|
||||
|
||||
cxt->dump.active = true;
|
||||
kmsg_dump_rewind(&cxt->dump);
|
||||
mtdoops_do_dump(&cxt->dump,(enum mtd_dump_reason)reason);
|
||||
cxt->dump.active = false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtdoops_do_dump_if);
|
||||
|
||||
|
||||
static int mtdoops_reboot_nb_handle(struct notifier_block *this, unsigned long event,
|
||||
void *ptr)
|
||||
{
|
||||
//char *cmd = ptr;
|
||||
enum mtd_dump_reason reason;
|
||||
|
||||
if (event == SYS_RESTART)
|
||||
reason = MTD_DUMP_RESTART;
|
||||
else if(event == SYS_POWER_OFF)
|
||||
reason = MTD_DUMP_POWEROFF;
|
||||
else
|
||||
return NOTIFY_OK;
|
||||
|
||||
mtdoops_do_dump_if(reason);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
|
||||
static void mtdoops_notify_add(struct mtd_info *mtd)
|
||||
{
|
||||
struct mtdoops_context *cxt = &oops_cxt;
|
||||
@ -326,8 +538,9 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
|
||||
return;
|
||||
}
|
||||
|
||||
cxt->dump.max_reason = KMSG_DUMP_OOPS;
|
||||
cxt->dump.dump = mtdoops_do_dump;
|
||||
// for panic
|
||||
cxt->dump.max_reason = KMSG_DUMP_MAX;
|
||||
cxt->dump.dump = mtdoops_do_dump_kmsgdump;
|
||||
err = kmsg_dump_register(&cxt->dump);
|
||||
if (err) {
|
||||
printk(KERN_ERR "mtdoops: registering kmsg dumper failed, error %d\n", err);
|
||||
@ -336,6 +549,12 @@ static void mtdoops_notify_add(struct mtd_info *mtd)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// for restart and power off
|
||||
cxt->reboot_nb.notifier_call = mtdoops_reboot_nb_handle;
|
||||
cxt->reboot_nb.priority = 255;
|
||||
register_reboot_notifier(&cxt->reboot_nb);
|
||||
|
||||
cxt->mtd = mtd;
|
||||
cxt->oops_pages = (int)mtd->size / record_size;
|
||||
find_next_position(cxt);
|
||||
@ -352,6 +571,8 @@ static void mtdoops_notify_remove(struct mtd_info *mtd)
|
||||
if (kmsg_dump_unregister(&cxt->dump) < 0)
|
||||
printk(KERN_WARNING "mtdoops: could not unregister kmsg_dumper\n");
|
||||
|
||||
unregister_reboot_notifier(&cxt->reboot_nb);
|
||||
|
||||
cxt->mtd = NULL;
|
||||
flush_work(&cxt->work_erase);
|
||||
flush_work(&cxt->work_write);
|
||||
@ -363,12 +584,94 @@ static struct mtd_notifier mtdoops_notifier = {
|
||||
.remove = mtdoops_notify_remove,
|
||||
};
|
||||
|
||||
static int mtdoops_parse_dt_u32(struct platform_device *pdev,
|
||||
const char *propname,
|
||||
u32 default_value, u32 *value)
|
||||
{
|
||||
u32 val32 = 0;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node, propname, &val32);
|
||||
if (ret == -EINVAL) {
|
||||
/* field is missing, use default value. */
|
||||
val32 = default_value;
|
||||
} else if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to parse property %s: %d\n",
|
||||
propname, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Sanity check our results. */
|
||||
if (val32 > INT_MAX) {
|
||||
dev_err(&pdev->dev, "%s %u > INT_MAX\n", propname, val32);
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
*value = val32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int mtdoops_pmsg_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mtdoops_context *cxt = &oops_cxt;
|
||||
struct resource *res;
|
||||
u32 value;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&pdev->dev, "using Device Tree\n");
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to locate DT /reserved-memory resource\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cxt->pmsg_data.mem_size = resource_size(res);
|
||||
cxt->pmsg_data.mem_address = res->start;
|
||||
|
||||
|
||||
#define parse_u32(name, field, default_value) { \
|
||||
ret = mtdoops_parse_dt_u32(pdev, name, default_value, \
|
||||
&value); \
|
||||
if (ret < 0) \
|
||||
return ret; \
|
||||
field = value; \
|
||||
}
|
||||
parse_u32("console-size", cxt->pmsg_data.console_size, 0);
|
||||
parse_u32("pmsg-size", cxt->pmsg_data.pmsg_size, 0);
|
||||
#undef parse_u32
|
||||
|
||||
printk(KERN_ERR "mtdoops: pares mtd_dt, mem_address =0x%x, mem_size =0x%x \n", cxt->pmsg_data.mem_address, cxt->pmsg_data.mem_size);
|
||||
printk(KERN_ERR "mtdoops: pares mtd_dt, pmsg_size =0x%x \n", cxt->pmsg_data.pmsg_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct of_device_id dt_match[] = {
|
||||
{ .compatible = "mtdoops_pmsg" },
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
static struct platform_driver mtdoops_pmsg_driver = {
|
||||
.probe = mtdoops_pmsg_probe,
|
||||
.driver = {
|
||||
.name = "mtdoops_pmsg",
|
||||
.of_match_table = dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mtdoops_init(void)
|
||||
{
|
||||
struct mtdoops_context *cxt = &oops_cxt;
|
||||
int mtd_index;
|
||||
char *endp;
|
||||
|
||||
printk(KERN_ERR "mtdoops: %s \n",__func__);
|
||||
|
||||
if (strlen(mtddev) == 0) {
|
||||
printk(KERN_ERR "mtdoops: mtd device (mtddev=name/number) must be supplied\n");
|
||||
return -EINVAL;
|
||||
@ -388,7 +691,8 @@ static int __init mtdoops_init(void)
|
||||
if (*endp == '\0')
|
||||
cxt->mtd_index = mtd_index;
|
||||
|
||||
cxt->oops_buf = vmalloc(record_size);
|
||||
//cxt->oops_buf = vmalloc(record_size);
|
||||
cxt->oops_buf = kmalloc(record_size, GFP_KERNEL);
|
||||
if (!cxt->oops_buf) {
|
||||
printk(KERN_ERR "mtdoops: failed to allocate buffer workspace\n");
|
||||
return -ENOMEM;
|
||||
@ -396,8 +700,12 @@ static int __init mtdoops_init(void)
|
||||
memset(cxt->oops_buf, 0xff, record_size);
|
||||
|
||||
INIT_WORK(&cxt->work_erase, mtdoops_workfunc_erase);
|
||||
|
||||
// we should write log immediately , if use work to write, ufs will shutdown before write log finish
|
||||
INIT_WORK(&cxt->work_write, mtdoops_workfunc_write);
|
||||
|
||||
platform_driver_register(&mtdoops_pmsg_driver);
|
||||
|
||||
register_mtd_user(&mtdoops_notifier);
|
||||
return 0;
|
||||
}
|
||||
@ -407,7 +715,7 @@ static void __exit mtdoops_exit(void)
|
||||
struct mtdoops_context *cxt = &oops_cxt;
|
||||
|
||||
unregister_mtd_user(&mtdoops_notifier);
|
||||
vfree(cxt->oops_buf);
|
||||
kfree(cxt->oops_buf);
|
||||
vfree(cxt->oops_page_used);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user