blob: bcb6a53d7fedd600196cb97419f470c43ba97fa2 [file] [log] [blame]
/*******************************************************************************
* °æÈ¨ËùÓÐ (C)2016, ÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£
*
* ÎļþÃû³Æ: ramdump_client_cap.c
* Îļþ±êʶ: ramdump_client_cap.c
* ÄÚÈÝÕªÒª: ramdump cap¿Í»§¶ËÒì³£ËÀ»úÏÖ³¡Êý¾Ýµ¼³öʵÏÖ
*
* ÐÞ¸ÄÈÕÆÚ °æ±¾ºÅ Ð޸ıê¼Ç ÐÞ¸ÄÈË ÐÞ¸ÄÄÚÈÝ
* ------------------------------------------------------------------------------
* 2019/10/10 V1.0 Create 00130574 ´´½¨
*
*******************************************************************************/
/*******************************************************************************
* Í·Îļþ *
*******************************************************************************/
#include "ramdump.h"
#include "ramdump_arch.h"
#include <linux/module.h>
#include <linux/soc/zte/rpmsg.h>
#include "ram_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
* ³£Á¿¶¨Òå *
*******************************************************************************/
/*******************************************************************************
* ºê¶¨Òå *
*******************************************************************************/
/*******************************************************************************
* Êý¾ÝÀàÐͶ¨Òå *
*******************************************************************************/
/*******************************************************************************
* º¯ÊýÉùÃ÷ *
*******************************************************************************/
extern void ramdump_register_callbacks(void);
extern unsigned char *ramdump_phy_to_vir(unsigned long phy, unsigned long size);
extern void ramdump_shared_mem_init(void);
extern void ramdump_data_transfer_to_device(void);
extern void ramdump_oss_data_trans_init(void);
extern unsigned char *ramdump_export_flag_base;
/*******************************************************************************
* ¾Ö²¿¾²Ì¬±äÁ¿¶¨Òå *
*******************************************************************************/
#define RAMDUMP_ON_DEFAULT_VAL (1)
/*******************************************************************************
* È«¾Ö±äÁ¿¶¨Òå *
*******************************************************************************/
/*
* run time control dump or not, use ( echo "0" > ramdump_on ) to close ramdump
*/
int sysctl_ramdump_on_panic = RAMDUMP_ON_DEFAULT_VAL;
int ramdump_cap_init_flag = -1;
int ramdump_count = 0;
int ramdump_server_exp_core = RAMDUMP_FALSE;
#ifdef CONFIG_RAMDUMP_USER
unsigned int sysctl_ramdump_on_user = 1;
#endif
unsigned int ramdump_export_mode = 0xFF;
/* Cmm file content */
unsigned char *ramdump_cap_cmm_buf = NULL;
/* err log file */
unsigned char *ramdump_cap_error_log = NULL;
unsigned int *cap_ddr_len_base = NULL;
unsigned int sysctl_ramdump_emmc_size = 0x0;
unsigned int sysctl_ramdump_emmc_start_addr = 0xFFFF;
static struct ctl_table cfg_ramdump_array[] = {
#ifdef CONFIG_RAMDUMP_USER
{
.procname = "sysctl_ramdump_on_user",
.data = &sysctl_ramdump_on_user,
.maxlen = sizeof(sysctl_ramdump_on_user),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
#endif
{
.procname = "ramdump_start_addr",
.data = &sysctl_ramdump_emmc_start_addr,
.maxlen = sizeof(u64),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
},
{
.procname = "ramdump_emmc_size",
.data = &sysctl_ramdump_emmc_size,
.maxlen = sizeof(u64),
.mode = 0644,
.proc_handler = proc_doulongvec_minmax,
},
{ }
};
static struct ctl_table sysctl_ramdump_table[] = {
{
.procname = "ramdump_ap",
.mode = 0555,
.child = cfg_ramdump_array,
},
{ }
};
/*******************************************************************************
* ¾Ö²¿º¯ÊýʵÏÖ *
*******************************************************************************/
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_cap_icp_handle
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) buf: icp msg addr
* len: icp msg len
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: This function is used for ramdump client icp msg handle, common entry
*******************************************************************************/
static void ramdump_cap_icp_handle(void *buf, unsigned int len)
{
ramdump_msg_t *icp_msg = (ramdump_msg_t *)buf;
ramdump_server_exp_core = RAMDUMP_SUCCESS;
switch(icp_msg->msg_id)
{
case RAMDUMP_MSG_EXCEPT:
{
ramdump_panic("trans server received forced dump request from Ap server!\n");
break;
}
default:
{
ramdump_panic("trans server received forced dump request from Ap server!\n");
break;
}
}
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_oss_icp_create_channel
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) actorID: icp send core id
chID: icp channel id
size: icp channel size
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: int: if msg send success
* ÆäËü˵Ã÷:
*******************************************************************************/
static int ramdump_cap_icp_create_channel(T_RpMsg_CoreID dstCoreID, T_RpMsg_ChID chID, unsigned int size)
{
return rpmsgCreateChannel(dstCoreID, chID, size);
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_oss_icp_regcallback
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) actorID: icp send core id
chID: icp channel id
callback:icp callback fun
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: int: if msg send success
* ÆäËü˵Ã÷:
*******************************************************************************/
static int ramdump_cap_icp_regcallback (T_RpMsg_CoreID coreID, unsigned int chID, T_RpMsg_Callback callback)
{
return rpmsgRegCallBack(coreID, chID, callback);
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_init_sysctl_table
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: ×¢²ásysctlÃüÁÓû§Ì¬Ê¹ÓÃsysctl¿ØÖÆramdump´æ´¢µØÖ·
*******************************************************************************/
void ramdump_init_sysctl_table(void)
{
register_sysctl_table(sysctl_ramdump_table);
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_cap_icp_init
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: This function is used for ramdump client icp init
*******************************************************************************/
static int ramdump_cap_icp_init(void)
{
int ret = 0;
ret = ramdump_cap_icp_create_channel(
RAMDUMP_SERVER_AP,
RAMDUMP_CHANNEL,
RAMDUMP_CHANNEL_SIZE);
if (ret != RAMDUMP_SUCCESS)
{
return ret;
}
ret = ramdump_cap_icp_regcallback(
RAMDUMP_SERVER_AP,
RAMDUMP_CHANNEL,
ramdump_cap_icp_handle);
if (ret != RAMDUMP_SUCCESS)
{
return ret;
}
return RAMDUMP_SUCCESS;
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_notify_server_panic
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: This function is used for cap notify ramdump server to panic
*******************************************************************************/
static int ramdump_notify_server_panic(void)
{
int ret = 0;
T_RpMsg_Msg rpMsg = {0};
ramdump_msg_t ramdumpMsg = {0};
ramdumpMsg.msg_id = RAMDUMP_MSG_EXCEPT;
ramdumpMsg.cpu_id = CORE_AP;
rpMsg.coreID = RAMDUMP_SERVER_AP;
rpMsg.chID = RAMDUMP_CHANNEL;
rpMsg.flag = RPMSG_WRITE_INT | RPMSG_WRITE_IRQLOCK;
rpMsg.len = sizeof(ramdump_msg_t);
rpMsg.buf = &ramdumpMsg;
ret = rpmsgWrite(&rpMsg);
return ret;
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_cap_store_ram_conf
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) mem: addr
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: unsigend char*: changed addr
* ÆäËü˵Ã÷: This function is used to store ram conf
*******************************************************************************/
static unsigned char *ramdump_cap_store_ram_conf(unsigned char *mem)
{
mem += sprintf(
mem,
"data.load.binary &ramdump_dir\\%s A:0x%x--A:0x%x /noclear\n",
"cap_ddr.bin",
(unsigned int)DDR_BASE_CAP_ADDR_PA,
(unsigned int)(DDR_BASE_CAP_ADDR_PA + *cap_ddr_len_base - 1));
mem += sprintf(
mem,
"data.load.binary &ramdump_dir\\%s A:0x%x--A:0x%x /noclear\n",
"cap.cmm",
(unsigned int)RAMDUMP_CAP_CMM_BUF_ADDR,
(unsigned int)(RAMDUMP_CAP_CMM_BUF_ADDR + RAMDUMP_CAP_CMM_BUF_LEN_REAL - 1));
mem += sprintf(
mem,
"data.load.binary &ramdump_dir\\%s A:0x%x--A:0x%x /noclear\n",
"cap_err_log.txt",
(unsigned int)RAMDUMP_CAP_LOG_BUF_ADDR,
(unsigned int)(RAMDUMP_CAP_LOG_BUF_ADDR + RAMDUMP_CAP_LOG_BUF_LEN - 1));
return mem;
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_cap_cmm_create
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: This function is used for server to generate cmm scripts
*******************************************************************************/
static void ramdump_cap_cmm_create(void)
{
unsigned char *pcmm_buf = ramdump_cap_cmm_buf;
memset(ramdump_cap_cmm_buf, 0, RAMDUMP_CAP_CMM_BUF_LEN_REAL);
// store the cmm BEGIN
pcmm_buf += sprintf(pcmm_buf, "ENTRY &ramdump_dir\n");
// store procmodes regs
pcmm_buf = ramdump_arch_store_modes_regs(pcmm_buf);
// store ram config
pcmm_buf = ramdump_cap_store_ram_conf(pcmm_buf);
// store memory map control regs
pcmm_buf = ramdump_arch_store_mm_regs(pcmm_buf);
// store end symbol
pcmm_buf += sprintf(pcmm_buf, "ENDDO\n");
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_trans_cap_error_log_create
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: This function is used to create err log file
*******************************************************************************/
static void ramdump_cap_error_log_create(void)
{
unsigned char *buf = ramdump_cap_error_log;
memset(ramdump_cap_error_log, 0, RAMDUMP_CAP_LOG_BUF_LEN);
buf += sprintf(buf, "dump at core%d,", smp_processor_id());
if (current->mm != NULL)
buf += sprintf(buf, "in user,task is: %s\n", current->comm);
else
buf += sprintf(buf, "in kernel,task is: %s\n", current->comm);
if (ramdump_server_exp_core)
buf += sprintf(buf, "recv dumpinfo from ap\n");
}
/*******************************************************************************
* È«¾Öº¯ÊýʵÏÖ *
*******************************************************************************/
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_ram_conf_table_add
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) ram_name: dump ram name
ram_start: dump ram start(virtual addr)
ram_size: dump ram size
ram_virt: dump ram virt addr
ram_flag: dump ram flag(copy/exter/callback)
ram_extra: dump ram extra access addr
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: This function is used to add dump ram conf into public table
*******************************************************************************/
void ramdump_ram_conf_table_add(
char *ram_name,
unsigned long ram_phy,
unsigned long ram_size,
unsigned long ram_virt,
unsigned long ram_flag,
unsigned long ram_extra)
{
}
void ramdump_init_cmm_buf(void)
{
/* Cmm file content */
ramdump_cap_cmm_buf = ramdump_phy_to_vir((unsigned long)RAMDUMP_CAP_CMM_BUF_ADDR, RAMDUMP_CAP_CMM_BUF_LEN_REAL);
/* err log file */
ramdump_cap_error_log = ramdump_phy_to_vir((unsigned long)RAMDUMP_CAP_LOG_BUF_ADDR, RAMDUMP_CAP_LOG_BUF_LEN);
cap_ddr_len_base = (unsigned int *)ramdump_phy_to_vir((unsigned long)IRAM_BASE_ADDR_BOOT_DDR, sizeof(unsigned long));
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_init
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: RAMDUMP_SUCCESS or RAMDUMP_FAILED
* ÆäËü˵Ã÷: This function is used for ramdump init
*******************************************************************************/
int __init ramdump_init(void)
{
int ret = 0;
ramdump_printf("Ramdump cap init start!!!!!\n");
if (ramdump_cap_init_flag == RAMDUMP_TRUE)
return RAMDUMP_SUCCESS;
ramdump_printf("Ramdump cap init rpmsg start!!!!!\n");
ret = ramdump_cap_icp_init();
if (ret != RAMDUMP_ICP_SUCCESS)
return ret;
ramdump_register_callbacks();
ramdump_init_cmm_buf();
ramdump_init_sysctl_table();
ramdump_shared_mem_init();
ramdump_oss_data_trans_init();
ramdump_printf("Ramdump cap init success!\n");
ramdump_cap_init_flag = RAMDUMP_TRUE;
return RAMDUMP_SUCCESS;
}
/*******************************************************************************
* ¹¦ÄÜÃèÊö: ramdump_entry
* ²ÎÊý˵Ã÷:
* (´«Èë²ÎÊý) void
* (´«³ö²ÎÊý) void
* ·µ »Ø Öµ: void
* ÆäËü˵Ã÷: This function is used for ramdump entry
*******************************************************************************/
void ramdump_entry (void)
{
unsigned long flags;
if (sysctl_ramdump_on_panic == false)
return;
/*
* we need lock the irq, this can`t be interrupt.
*/
ramdump_irq_lock(flags);
if (!ramdump_cap_init_flag)
while(true); /* endless circle */
if (++ramdump_count > 1)
while(true); /* endless circle */
/*
* save all regs first.
*/
ramdump_arch_save_all_regs();
// generate error log
ramdump_cap_error_log_create();
//Éú³Écmm½Å±¾µÄµ¼³öÅäÖÃ
ramdump_cap_cmm_create();
/* notify client ramdump */
ramdump_notify_server_panic();
ramdump_arch_clean_caches();
ramdump_export_mode = *(unsigned int *)ramdump_export_flag_base;
if((ramdump_export_mode == RAMDUMP_MODE_EMMC)
|| (ramdump_export_mode == RAMDUMP_MODE_SPINAND))
ramdump_data_transfer_to_device();
while(true)
;
}
#ifdef __cplusplus
}
#endif