aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/mediatek/eccci/port_kernel.c
diff options
context:
space:
mode:
authorMeizu OpenSource <patchwork@meizu.com>2016-08-15 10:19:42 +0800
committerMeizu OpenSource <patchwork@meizu.com>2016-08-15 10:19:42 +0800
commitd2e1446d81725c351dc73a03b397ce043fb18452 (patch)
tree4dbc616b7f92aea39cd697a9084205ddb805e344 /drivers/misc/mediatek/eccci/port_kernel.c
downloadandroid_kernel_m2note-d2e1446d81725c351dc73a03b397ce043fb18452.tar.gz
first commit
Diffstat (limited to 'drivers/misc/mediatek/eccci/port_kernel.c')
-rw-r--r--drivers/misc/mediatek/eccci/port_kernel.c1899
1 files changed, 1899 insertions, 0 deletions
diff --git a/drivers/misc/mediatek/eccci/port_kernel.c b/drivers/misc/mediatek/eccci/port_kernel.c
new file mode 100644
index 000000000..19dee611d
--- /dev/null
+++ b/drivers/misc/mediatek/eccci/port_kernel.c
@@ -0,0 +1,1899 @@
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/rtc.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <mach/mt_gpio.h>
+#include <mach/mt_sec_export.h>
+
+#if defined (CONFIG_MTK_AEE_FEATURE)
+#include <linux/aee.h>
+#else
+#define DB_OPT_DEFAULT (0) // Dummy macro define to avoid build error
+#define DB_OPT_FTRACE (0) // Dummy macro define to avoid build error
+#endif
+#include <mach/ccci_config.h>
+
+#ifdef FEATURE_RF_CLK_BUF
+
+#if defined(CONFIG_MTK_LEGACY)
+#include <cust_clk_buf.h>
+#endif
+
+#include <mach/mt_clkbuf_ctl.h>
+#endif
+#include "ccci_core.h"
+#include "ccci_bm.h"
+#include "ccci_platform.h"
+#include "port_kernel.h"
+
+#if defined (FEATURE_GET_MD_ADC_NUM)
+extern int IMM_get_adc_channel_num(char *channel_name, int len);
+#endif
+#if defined (FEATURE_GET_MD_ADC_VAL)
+extern int IMM_GetOneChannelValue(int dwChannel, int data[4], int* rawdata);
+#endif
+
+#if defined(FEATURE_GET_MD_PMIC_ADC_VAL)
+extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd);
+#endif
+
+#if defined (FEATURE_GET_MD_PMIC_ADC_NUM)
+extern int PMIC_IMM_get_adc_channel_num(char *adc_name, int len);
+#endif
+
+#if defined (FEATURE_GET_DRAM_TYPE_CLK)
+extern int get_dram_info(int *clk, int *type);
+#endif
+#if defined (FEATURE_GET_MD_EINT_ATTR)
+extern int get_eint_attribute(char *name, unsigned int name_len, unsigned int type, char * result, unsigned int *len);
+#endif
+static void ccci_ee_info_dump(struct ccci_modem *md);
+static void ccci_aed(struct ccci_modem *md, unsigned int dump_flag, char *aed_str, int db_opt);
+extern void ccci_set_dsp_region_protection(struct ccci_modem *md, int loaded);
+#define MAX_QUEUE_LENGTH 16
+#define EX_TIMER_SWINT 10
+#define EX_TIMER_MD_EX 5
+#define EX_TIMER_MD_EX_REC_OK 10
+#define EX_TIMER_MD_HANG 5
+
+/*
+ * all supported modems should follow these handshake messages as a protocol.
+ * but we still can support un-usual modem by providing cutomed kernel_port_ops.
+ */
+static void control_msg_handler(struct ccci_port *port, struct ccci_request *req)
+{
+ struct ccci_modem *md = port->modem;
+ struct ccci_header *ccci_h = (struct ccci_header *)req->skb->data;
+ unsigned long flags;
+ char need_update_state = 0;
+
+ CCCI_INF_MSG(md->index, KERN, "control message 0x%X,0x%X\n", ccci_h->data[1], ccci_h->reserved);
+ if(ccci_h->data[1] == MD_INIT_START_BOOT
+ && ccci_h->reserved == MD_INIT_CHK_ID
+ && md->boot_stage == MD_BOOT_STAGE_0) {
+ del_timer(&md->bootup_timer);
+ md->boot_stage = MD_BOOT_STAGE_1;
+ ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_BOOT_UP, 0);
+ } else if(ccci_h->data[1] == MD_NORMAL_BOOT
+ && md->boot_stage == MD_BOOT_STAGE_1) {
+ del_timer(&md->bootup_timer);
+ md->boot_stage = MD_BOOT_STAGE_2;
+ md->ops->broadcast_state(md, READY);
+ ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_BOOT_READY, 0);
+ } else if(ccci_h->data[1] == MD_EX) {
+ if (unlikely(ccci_h->reserved != MD_EX_CHK_ID)) {
+ CCCI_ERR_MSG(md->index, KERN, "receive invalid MD_EX\n");
+ } else {
+ spin_lock_irqsave(&md->ctrl_lock, flags);
+ //md->boot_stage = MD_BOOT_STAGE_EXCEPTION;
+ md->ee_info_flag |= ((1<<MD_EE_FLOW_START)|(1<<MD_EE_MSG_GET)|(1<<MD_STATE_UPDATE)|\
+ (1<<MD_EE_TIME_OUT_SET));
+ md->config.setting |= MD_SETTING_RELOAD;
+ spin_unlock_irqrestore(&md->ctrl_lock, flags);
+ del_timer(&md->bootup_timer);
+ if(!MD_IN_DEBUG(md))
+ mod_timer(&md->ex_monitor, jiffies+EX_TIMER_MD_EX*HZ);
+ md->ops->broadcast_state(md, EXCEPTION);
+ ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_EXCEPTION, 0);
+ ccci_send_msg_to_md(md, CCCI_CONTROL_TX, MD_EX, MD_EX_CHK_ID, 1);
+
+ CCCI_INF_MSG(md->index, KERN, "Disable WDT at exception enter.");
+ md->ops->ee_callback(md, EE_FLAG_DISABLE_WDT);
+ }
+ } else if(ccci_h->data[1] == MD_EX_REC_OK) {
+ if (unlikely(ccci_h->reserved!=MD_EX_REC_OK_CHK_ID || req->skb->len<(sizeof(struct ccci_header)+sizeof(EX_LOG_T)))) {
+ CCCI_ERR_MSG(md->index, KERN, "receive invalid MD_EX_REC_OK, resv=%x, len=%d\n", ccci_h->reserved, req->skb->len);
+ } else {
+ spin_lock_irqsave(&md->ctrl_lock, flags);
+ md->ee_info_flag |= ((1<<MD_EE_FLOW_START)|(1<<MD_EE_OK_MSG_GET));
+ if((md->ee_info_flag & (1<<MD_STATE_UPDATE)) == 0) {
+ md->ee_info_flag |= (1<<MD_STATE_UPDATE);
+ md->ee_info_flag &= ~(1<<MD_EE_TIME_OUT_SET);
+ //md->boot_stage = MD_BOOT_STAGE_EXCEPTION;
+ md->config.setting |= MD_SETTING_RELOAD;
+ need_update_state = 1;
+ }
+ spin_unlock_irqrestore(&md->ctrl_lock, flags);
+ if(need_update_state) {
+ CCCI_ERR_MSG(md->index, KERN, "get MD_EX_REC_OK without exception MD_EX\n");
+ del_timer(&md->bootup_timer);
+ md->ops->broadcast_state(md, EXCEPTION);
+ }
+ // copy exception info
+ memcpy(&md->ex_info, skb_pull(req->skb, sizeof(struct ccci_header)), sizeof(EX_LOG_T));
+ mod_timer(&md->ex_monitor, jiffies);
+ }
+ }else if (ccci_h->data[1] == MD_EX_PASS) {
+ // dump share memory again to let MD check exception flow
+ mod_timer(&md->ex_monitor2, jiffies);
+ }else if (ccci_h->data[1] == MD_INIT_START_BOOT
+ && ccci_h->reserved == MD_INIT_CHK_ID
+ && !(md->config.setting&MD_SETTING_FIRST_BOOT)) {
+ md->boot_stage = MD_BOOT_STAGE_0;
+ CCCI_ERR_MSG(md->index, KERN, "MD second bootup detected!\n");
+ ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_RESET, 0);
+ } else if (ccci_h->data[1] == MD_EX_RESUME) {
+ memset(&md->debug_info, 0, sizeof(md->debug_info));
+ md->debug_info.type = MD_EX_TYPE_EMI_CHECK;
+ md->debug_info.name = "EMI_CHK";
+ md->debug_info.data = *(ccci_msg_t *)ccci_h;
+ md->ex_type = MD_EX_TYPE_EMI_CHECK;
+ ccci_ee_info_dump(md);
+ } else if (ccci_h->data[1] == CCCI_DRV_VER_ERROR) {
+ CCCI_ERR_MSG(md->index, KERN, "AP CCCI driver version mis-match to MD!!\n");
+ md->config.setting |= MD_SETTING_STOP_RETRY_BOOT;
+ ccci_aed(md, 0, "AP/MD driver version mis-match\n", DB_OPT_DEFAULT);
+ } else {
+ CCCI_ERR_MSG(md->index, KERN, "receive unknow data from CCCI_CONTROL_RX = %d\n", ccci_h->data[1]);
+ }
+ req->policy = RECYCLE;
+ ccci_free_req(req);
+}
+
+// for backward compatibility
+ccci_sys_cb_func_info_t ccci_sys_cb_table_100[MAX_MD_NUM][MAX_KERN_API];
+ccci_sys_cb_func_info_t ccci_sys_cb_table_1000[MAX_MD_NUM][MAX_KERN_API];
+int register_ccci_sys_call_back(int md_id, unsigned int id, ccci_sys_cb_func_t func)
+{
+ int ret = 0;
+ ccci_sys_cb_func_info_t *info_ptr;
+
+ if( md_id >= MAX_MD_NUM ) {
+ CCCI_ERR_MSG(md_id, KERN, "register_sys_call_back fail: invalid md id\n");
+ return -EINVAL;
+ }
+
+ if((id >= 0x100)&&((id-0x100) < MAX_KERN_API)) {
+ info_ptr = &(ccci_sys_cb_table_100[md_id][id-0x100]);
+ } else if((id >= 0x1000)&&((id-0x1000) < MAX_KERN_API)) {
+ info_ptr = &(ccci_sys_cb_table_1000[md_id][id-0x1000]);
+ } else {
+ CCCI_ERR_MSG(md_id, KERN, "register_sys_call_back fail: invalid func id(0x%x)\n", id);
+ return -EINVAL;
+ }
+
+ if(info_ptr->func == NULL) {
+ info_ptr->id = id;
+ info_ptr->func = func;
+ }
+ else {
+ CCCI_ERR_MSG(md_id, KERN, "register_sys_call_back fail: func(0x%x) registered!\n", id);
+ }
+
+ return ret;
+}
+
+void exec_ccci_sys_call_back(int md_id, int cb_id, int data)
+{
+ ccci_sys_cb_func_t func;
+ int id;
+ ccci_sys_cb_func_info_t *curr_table;
+
+ if(md_id >= MAX_MD_NUM) {
+ CCCI_ERR_MSG(md_id, KERN, "exec_sys_cb fail: invalid md id\n");
+ return;
+ }
+
+ id = cb_id & 0xFF;
+ if(id >= MAX_KERN_API) {
+ CCCI_ERR_MSG(md_id, KERN, "exec_sys_cb fail: invalid func id(0x%x)\n", cb_id);
+ return;
+ }
+
+ if ((cb_id & (0x1000|0x100))==0x1000) {
+ curr_table = ccci_sys_cb_table_1000[md_id];
+ } else if ((cb_id & (0x1000|0x100))==0x100) {
+ curr_table = ccci_sys_cb_table_100[md_id];
+ } else {
+ CCCI_ERR_MSG(md_id, KERN, "exec_sys_cb fail: invalid func id(0x%x)\n", cb_id);
+ return;
+ }
+
+ func = curr_table[id].func;
+ if(func != NULL) {
+ func(md_id, data);
+ } else {
+ CCCI_ERR_MSG(md_id, KERN, "exec_sys_cb fail: func id(0x%x) not register!\n", cb_id);
+ }
+}
+
+static void system_msg_handler(struct ccci_port *port, struct ccci_request *req)
+{
+ struct ccci_modem *md = port->modem;
+ struct ccci_header *ccci_h = (struct ccci_header *)req->skb->data;
+
+ CCCI_DBG_MSG(md->index, KERN, "system message (%x %x %x %x)\n", ccci_h->data[0], ccci_h->data[1], ccci_h->channel, ccci_h->reserved);
+ switch(ccci_h->data[1]) {
+ case MD_GET_BATTERY_INFO:
+ ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_SEND_BATTERY_INFO, 0);
+ break;
+ case MD_WDT_MONITOR:
+ // abandoned
+ break;
+ case MD_SIM_TYPE:
+ md->sim_type = ccci_h->reserved;
+ CCCI_INF_MSG(md->index, KERN, "MD send sys msg sim type(0x%x)\n",md->sim_type);
+ break;
+ case MD_TX_POWER:
+ case MD_RF_TEMPERATURE:
+ case MD_RF_TEMPERATURE_3G:
+#if defined(CONFIG_MTK_SWITCH_TX_POWER)
+ case MD_SW_MD1_TX_POWER_REQ:
+ case MD_SW_MD2_TX_POWER_REQ:
+#endif
+ exec_ccci_sys_call_back(md->index, ccci_h->data[1], ccci_h->reserved);
+ break;
+ };
+ req->policy = RECYCLE;
+ ccci_free_req(req);
+}
+
+static int get_md_gpio_val(unsigned int num)
+{
+#if defined (FEATURE_GET_MD_GPIO_VAL)
+ return mt_get_gpio_in(num);
+#else
+ return -1;
+#endif
+}
+
+static int get_md_adc_val(unsigned int num)
+{
+#if defined (FEATURE_GET_MD_ADC_VAL)
+ int data[4] = {0,0,0,0};
+ int val = 0;
+ int ret = 0;
+ CCCI_INF_MSG(0, RPC, "FEATURE_GET_MD_ADC_VAL \n");
+ ret = IMM_GetOneChannelValue(num, data, &val);
+ if (ret == 0)
+ return val;
+ else
+ return ret;
+#elif defined(FEATURE_GET_MD_PMIC_ADC_VAL)
+ CCCI_INF_MSG(0, RPC, "FEATURE_GET_MD_PMIC_ADC_VAL \n");
+ return PMIC_IMM_GetOneChannelValue(num, 1, 0);
+#else
+ return -1;
+#endif
+}
+
+static int get_td_eint_info(char *eint_name, unsigned int len)
+{
+#if defined (FEATURE_GET_TD_EINT_NUM)
+ return get_td_eint_num(eint_name, len);
+#else
+ return -1;
+#endif
+}
+
+static int get_md_adc_info(char *adc_name, unsigned int len)
+{
+#if defined (FEATURE_GET_MD_ADC_NUM)
+ CCCI_INF_MSG(0, RPC, "FEATURE_GET_MD_ADC_NUM \n");
+ return IMM_get_adc_channel_num(adc_name, len);
+#elif defined(FEATURE_GET_MD_PMIC_ADC_NUM)
+ CCCI_INF_MSG(0, RPC, "FEATURE_GET_MD_PMIC_ADC_NUM \n");
+ return PMIC_IMM_get_adc_channel_num(adc_name, len);
+#else
+ return -1;
+#endif
+}
+
+static int get_md_gpio_info(char *gpio_name, unsigned int len)
+{
+#if defined (FEATURE_GET_MD_GPIO_NUM)
+ return mt_get_md_gpio(gpio_name, len);
+#else
+ return -1;
+#endif
+}
+
+static int get_dram_type_clk(int *clk, int *type)
+{
+#if defined (FEATURE_GET_DRAM_TYPE_CLK)
+ return get_dram_info(clk, type);
+#else
+ return -1;
+#endif
+}
+
+static int get_eint_attr(char *name, unsigned int name_len, unsigned int type, char *result, unsigned int *len)
+{
+#if defined (FEATURE_GET_MD_EINT_ATTR)
+ return get_eint_attribute(name, name_len, type, result, len);
+#else
+ return -1;
+#endif
+}
+
+static void ccci_rpc_work_helper(struct ccci_modem *md, struct rpc_pkt *pkt,
+ struct rpc_buffer *p_rpc_buf, unsigned int tmp_data[])
+{
+ // tmp_data[] is used to make sure memory address is valid after this function return, be careful with the size!
+ int pkt_num = p_rpc_buf->para_num;
+
+ CCCI_DBG_MSG(md->index, RPC, "ccci_rpc_work_helper++ %d\n", p_rpc_buf->para_num);
+ tmp_data[0] = 0;
+ switch(p_rpc_buf->op_id) {
+ case IPC_RPC_CPSVC_SECURE_ALGO_OP:
+ {
+ unsigned char Direction = 0;
+ unsigned long ContentAddr = 0;
+ unsigned int ContentLen = 0;
+ sed_t CustomSeed = SED_INITIALIZER;
+ unsigned char *ResText __always_unused= NULL;
+ unsigned char *RawText __always_unused= NULL;
+ unsigned int i __always_unused= 0;
+
+ if(pkt_num < 4 || pkt_num >= RPC_MAX_ARG_NUM) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid pkt_num %d for RPC_SECURE_ALGO_OP!\n", pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+
+ Direction = *(unsigned char*)pkt[0].buf;
+ ContentAddr = (unsigned long)pkt[1].buf;
+ CCCI_DBG_MSG(md->index, RPC, "RPC_SECURE_ALGO_OP: Content_Addr = 0x%p, RPC_Base = 0x%p, RPC_Len = 0x%zu\n",
+ (void*)ContentAddr, p_rpc_buf, sizeof(unsigned int) + RPC_MAX_BUF_SIZE);
+ if(ContentAddr < (unsigned long)p_rpc_buf ||
+ ContentAddr > ((unsigned long)p_rpc_buf + sizeof(unsigned int) + RPC_MAX_BUF_SIZE)) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid ContentAdddr[0x%p] for RPC_SECURE_ALGO_OP!\n", (void*)ContentAddr);
+ tmp_data[0] = FS_PARAM_ERROR;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+ ContentLen = *(unsigned int*)pkt[2].buf;
+ // CustomSeed = *(sed_t*)pkt[3].buf;
+ WARN_ON(sizeof(CustomSeed.sed)<pkt[3].len);
+ memcpy(CustomSeed.sed,pkt[3].buf,pkt[3].len);
+
+#ifdef ENCRYPT_DEBUG
+ unsigned char log_buf[128];
+ int curr;
+
+ if(Direction == TRUE)
+ CCCI_INF_MSG(md->index, RPC, "HACC_S: EnCrypt_src:\n");
+ else
+ CCCI_INF_MSG(md->index, RPC, "HACC_S: DeCrypt_src:\n");
+ for(i = 0; i < ContentLen; i++) {
+ if(i % 16 == 0) {
+ if(i!=0) {
+ CCCI_INF_MSG(md->index, RPC, "%s\n", log_buf);
+ }
+ curr = 0;
+ curr += snprintf(log_buf, sizeof(log_buf)-curr, "HACC_S: ");
+ }
+ //CCCI_INF_MSG(md->index, RPC, "0x%02X ", *(unsigned char*)(ContentAddr+i));
+ curr += snprintf(&log_buf[curr], sizeof(log_buf)-curr, "0x%02X ", *(unsigned char*)(ContentAddr+i));
+ //sleep(1);
+ }
+ CCCI_INF_MSG(md->index, RPC, "%s\n", log_buf);
+
+ RawText = kmalloc(ContentLen, GFP_KERNEL);
+ if(RawText == NULL)
+ CCCI_ERR_MSG(md->index, RPC, "Fail alloc Mem for RPC_SECURE_ALGO_OP!\n");
+ else
+ memcpy(RawText, (unsigned char*)ContentAddr, ContentLen);
+#endif
+
+ ResText = kmalloc(ContentLen, GFP_KERNEL);
+ if(ResText == NULL) {
+ CCCI_ERR_MSG(md->index, RPC, "Fail alloc Mem for RPC_SECURE_ALGO_OP!\n");
+ tmp_data[0] = FS_PARAM_ERROR;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+
+#if (defined(ENABLE_MD_IMG_SECURITY_FEATURE) && defined(MTK_SEC_MODEM_NVRAM_ANTI_CLONE))
+ if(!masp_secure_algo_init()) {
+ CCCI_ERR_MSG(md->index, RPC, "masp_secure_algo_init fail!\n");
+ ASSERT(0);
+ }
+
+ CCCI_DBG_MSG(md->index, RPC, "RPC_SECURE_ALGO_OP: Dir=0x%08X, Addr=0x%08lX, Len=0x%08X, Seed=0x%016llX\n",
+ Direction, ContentAddr, ContentLen, *(long long *)CustomSeed.sed);
+ masp_secure_algo(Direction, ContentAddr, ContentLen, CustomSeed.sed, ResText);
+
+ if(!masp_secure_algo_deinit())
+ CCCI_ERR_MSG(md->index, RPC, "masp_secure_algo_deinit fail!\n");
+#endif
+
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = ContentLen;
+
+#if (defined(ENABLE_MD_IMG_SECURITY_FEATURE) && defined(MTK_SEC_MODEM_NVRAM_ANTI_CLONE))
+ memcpy(pkt[pkt_num++].buf, ResText, ContentLen);
+ CCCI_INF_MSG(md->index, RPC, "RPC_Secure memory copy OK: %d!", ContentLen);
+#else
+ memcpy(pkt[pkt_num++].buf, (void *)ContentAddr, ContentLen);
+ CCCI_INF_MSG(md->index, RPC, "RPC_NORMAL memory copy OK: %d!", ContentLen);
+#endif
+
+#ifdef ENCRYPT_DEBUG
+ if(Direction == TRUE)
+ CCCI_INF_MSG(md->index, RPC, "HACC_D: EnCrypt_dst:\n");
+ else
+ CCCI_INF_MSG(md->index, RPC, "HACC_D: DeCrypt_dst:\n");
+ for(i = 0; i < ContentLen; i++) {
+ if(i % 16 == 0){
+ if(i!=0){
+ CCCI_DBG_MSG(md->index, RPC, "%s\n", log_buf);
+ }
+ curr = 0;
+ curr += snprintf(&log_buf[curr], sizeof(log_buf)-curr, "HACC_D: ");
+ }
+ //CCCI_INF_MSG(md->index, RPC, "%02X ", *(ResText+i));
+ curr += snprintf(&log_buf[curr], sizeof(log_buf)-curr, "0x%02X ", *(ResText+i));
+ //sleep(1);
+ }
+
+ CCCI_INF_MSG(md->index, RPC, "%s\n", log_buf);
+
+ if(RawText)
+ kfree(RawText);
+#endif
+
+ kfree(ResText);
+ break;
+ }
+
+#ifdef ENABLE_MD_IMG_SECURITY_FEATURE
+ case IPC_RPC_GET_SECRO_OP:
+ {
+ unsigned char *addr = NULL;
+ unsigned int img_len = 0;
+ unsigned int img_len_bak = 0;
+ unsigned int blk_sz = 0;
+ unsigned int tmp = 1;
+ unsigned int cnt = 0;
+ unsigned int req_len = 0;
+
+ if(pkt_num != 1) {
+ CCCI_ERR_MSG(md->index, RPC, "RPC_GET_SECRO_OP: invalid parameter: pkt_num=%d \n", pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ tmp_data[1] = img_len;
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ break;
+ }
+
+ req_len = *(unsigned int*)(pkt[0].buf);
+ if(masp_secro_en()) {
+ img_len = masp_secro_md_len(md->post_fix);
+
+ if((img_len > RPC_MAX_BUF_SIZE) || (req_len > RPC_MAX_BUF_SIZE)) {
+ pkt_num = 0;
+ tmp_data[0] = FS_MEM_OVERFLOW;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ //set it as image length for modem ccci check when error happens
+ pkt[pkt_num].len = img_len;
+ ///pkt[pkt_num].len = sizeof(unsigned int);
+ tmp_data[1] = img_len;
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ CCCI_ERR_MSG(md->index, RPC, "RPC_GET_SECRO_OP: md request length is larger than rpc memory: (%d, %d) \n",
+ req_len, img_len);
+ break;
+ }
+
+ if(img_len > req_len) {
+ pkt_num = 0;
+ tmp_data[0] = FS_NO_MATCH;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ //set it as image length for modem ccci check when error happens
+ pkt[pkt_num].len = img_len;
+ ///pkt[pkt_num].len = sizeof(unsigned int);
+ tmp_data[1] = img_len;
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ CCCI_ERR_MSG(md->index, RPC, "RPC_GET_SECRO_OP: AP mis-match MD request length: (%d, %d) \n",
+ req_len, img_len);
+ break;
+ }
+
+ /* TODO : please check it */
+ /* save original modem secro length */
+ CCCI_DBG_MSG(md->index, RPC, "<rpc>RPC_GET_SECRO_OP: save MD SECRO length: (%d) \n",img_len);
+ img_len_bak = img_len;
+
+ blk_sz = masp_secro_blk_sz();
+ for(cnt = 0; cnt < blk_sz; cnt++) {
+ tmp = tmp*2;
+ if(tmp >= blk_sz)
+ break;
+ }
+ ++cnt;
+ img_len = ((img_len + (blk_sz-1)) >> cnt) << cnt;
+
+ addr = (unsigned char*)&(p_rpc_buf->para_num) + 4*sizeof(unsigned int);
+ tmp_data[0] = masp_secro_md_get_data(md->post_fix, addr, 0, img_len);
+
+ /* TODO : please check it */
+ /* restore original modem secro length */
+ img_len = img_len_bak;
+
+ CCCI_DBG_MSG(md->index, RPC, "<rpc>RPC_GET_SECRO_OP: restore MD SECRO length: (%d) \n",img_len);
+
+ if(tmp_data[0] != 0) {
+ CCCI_ERR_MSG(md->index, RPC, "RPC_GET_SECRO_OP: get data fail:%d \n", tmp_data[0]);
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ tmp_data[1] = img_len;
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ } else {
+ CCCI_DBG_MSG(md->index, RPC, "RPC_GET_SECRO_OP: get data OK: %d,%d \n", img_len, tmp_data[0]);
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ //pkt[pkt_num++].buf = (void*) &img_len;
+ tmp_data[1] = img_len;
+ pkt[pkt_num++].buf = (void*)&tmp_data[1];
+ pkt[pkt_num].len = img_len;
+ pkt[pkt_num++].buf = (void*) addr;
+ //tmp_data[2] = (unsigned int)addr;
+ //pkt[pkt_num++].buf = (void*) &tmp_data[2];
+ }
+ }else {
+ CCCI_INF_MSG(md->index, RPC, "RPC_GET_SECRO_OP: secro disable \n");
+ tmp_data[0] = FS_NO_FEATURE;
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ tmp_data[1] = img_len;
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ }
+
+ break;
+ }
+#endif
+
+ //call EINT API to get TDD EINT configuration for modem EINT initial
+ case IPC_RPC_GET_TDD_EINT_NUM_OP:
+ case IPC_RPC_GET_GPIO_NUM_OP:
+ case IPC_RPC_GET_ADC_NUM_OP:
+ {
+ int get_num = 0;
+ unsigned char * name = NULL;
+ unsigned int length = 0;
+
+ if(pkt_num<2 || pkt_num>RPC_MAX_ARG_NUM) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d!\n",
+ p_rpc_buf->op_id, pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ goto err1;
+ }
+
+ if((length = pkt[0].len) < 1) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d, name_len=%d!\n",
+ p_rpc_buf->op_id, pkt_num, length);
+ tmp_data[0] = FS_PARAM_ERROR;
+ goto err1;
+ }
+
+ name = kmalloc(length, GFP_KERNEL);
+ if(name == NULL) {
+ CCCI_ERR_MSG(md->index, RPC, "Fail alloc Mem for [0x%X]!\n", p_rpc_buf->op_id);
+ tmp_data[0] = FS_ERROR_RESERVED;
+ goto err1;
+ } else {
+ memcpy(name, (unsigned char*)(pkt[0].buf), length);
+
+ if(p_rpc_buf->op_id == IPC_RPC_GET_TDD_EINT_NUM_OP) {
+ if((get_num = get_td_eint_info(name, length)) < 0) {
+ get_num = FS_FUNC_FAIL;
+ }
+ } else if(p_rpc_buf->op_id == IPC_RPC_GET_GPIO_NUM_OP) {
+ if((get_num = get_md_gpio_info(name, length)) < 0) {
+ get_num = FS_FUNC_FAIL;
+ }
+ } else if(p_rpc_buf->op_id == IPC_RPC_GET_ADC_NUM_OP) {
+ if((get_num = get_md_adc_info(name, length)) < 0) {
+ get_num = FS_FUNC_FAIL;
+ }
+ }
+
+ CCCI_INF_MSG(md->index, RPC, "[0x%08X]: name:%s, len=%d, get_num:%d\n",p_rpc_buf->op_id,
+ name, length, get_num);
+ pkt_num = 0;
+
+ /* NOTE: tmp_data[1] not [0] */
+ tmp_data[1] = (unsigned int)get_num; // get_num may be invalid after exit this function
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*)(&tmp_data[1]);
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*)(&tmp_data[1]);
+ kfree(name);
+ }
+ break;
+
+err1:
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+
+ case IPC_RPC_GET_EMI_CLK_TYPE_OP:
+ {
+ int dram_type = 0;
+ int dram_clk = 0;
+
+ if(pkt_num != 0) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d!\n",
+ p_rpc_buf->op_id, pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ goto err2;
+ }
+
+ if(get_dram_type_clk(&dram_clk, &dram_type)) {
+ tmp_data[0] = FS_FUNC_FAIL;
+ goto err2;
+ } else {
+ tmp_data[0] = 0;
+ CCCI_INF_MSG(md->index, RPC, "[0x%08X]: dram_clk: %d, dram_type:%d \n",
+ p_rpc_buf->op_id, dram_clk, dram_type);
+ }
+
+ tmp_data[1] = (unsigned int)dram_type;
+ tmp_data[2] = (unsigned int)dram_clk;
+
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*)(&tmp_data[0]);
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*)(&tmp_data[1]);
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*)(&tmp_data[2]);
+ break;
+
+err2:
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+
+ case IPC_RPC_GET_EINT_ATTR_OP:
+ {
+ char * eint_name = NULL;
+ unsigned int name_len = 0;
+ unsigned int type = 0;
+ char * res = NULL;
+ unsigned int res_len = 0;
+ int ret = 0;
+
+ if(pkt_num<3 || pkt_num>RPC_MAX_ARG_NUM) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d!\n",
+ p_rpc_buf->op_id, pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ goto err3;
+ }
+
+ if((name_len = pkt[0].len) < 1) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d, name_len=%d!\n",
+ p_rpc_buf->op_id, pkt_num, name_len);
+ tmp_data[0] = FS_PARAM_ERROR;
+ goto err3;
+ }
+
+ eint_name = kmalloc(name_len, GFP_KERNEL);
+ if(eint_name == NULL) {
+ CCCI_ERR_MSG(md->index, RPC, "Fail alloc Mem for [0x%X]!\n", p_rpc_buf->op_id);
+ tmp_data[0] = FS_ERROR_RESERVED;
+ goto err3;
+ } else {
+ memcpy(eint_name, (unsigned char*)(pkt[0].buf), name_len);
+ }
+
+ type = *(unsigned int*)(pkt[2].buf);
+ res = (unsigned char*)&(p_rpc_buf->para_num) + 4*sizeof(unsigned int);
+ ret = get_eint_attr(eint_name, name_len, type, res, &res_len);
+ if (ret == 0) {
+ tmp_data[0] = ret;
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = res_len;
+ pkt[pkt_num++].buf = (void*) res;
+ CCCI_INF_MSG(md->index, RPC, "[0x%08X] OK: name:%s, len:%d, type:%d, res:%d, res_len:%d\n",
+ p_rpc_buf->op_id, eint_name, name_len, type, *res, res_len);
+ kfree(eint_name);
+ } else {
+ tmp_data[0] = ret;
+ CCCI_ERR_MSG(md->index, RPC, "[0x%08X] fail: name:%s, len:%d, type:%d, ret:%d\n", p_rpc_buf->op_id,
+ eint_name, name_len, type, ret);
+ kfree(eint_name);
+ goto err3;
+ }
+ break;
+
+err3:
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+#ifdef FEATURE_RF_CLK_BUF
+ case IPC_RPC_GET_RF_CLK_BUF_OP:
+ {
+ u16 count = 0;
+ struct ccci_rpc_clkbuf_result *clkbuf;
+ CLK_BUF_SWCTRL_STATUS_T swctrl_status[CLKBUF_MAX_COUNT];
+
+ if(pkt_num != 1) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d!\n",
+ p_rpc_buf->op_id, pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+ count = *(u16*)(pkt[0].buf);
+ pkt_num = 0;
+ tmp_data[0] = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(struct ccci_rpc_clkbuf_result);
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ clkbuf = (struct ccci_rpc_clkbuf_result*) &tmp_data[1];
+ if(count != CLKBUF_MAX_COUNT) {
+ CCCI_ERR_MSG(md->index, RPC, "IPC_RPC_GET_RF_CLK_BUF, wrong count %d/%d\n", count, CLKBUF_MAX_COUNT);
+ clkbuf->CLKBuf_Count = 0xFF;
+ memset(&clkbuf->CLKBuf_Status, 0, sizeof(clkbuf->CLKBuf_Status));
+ } else {
+#if !defined(CONFIG_MTK_LEGACY)
+ unsigned int CLK_BUF1_STATUS, CLK_BUF2_STATUS, CLK_BUF3_STATUS, CLK_BUF4_STATUS;
+ struct device_node *node;
+ node = of_find_compatible_node(NULL,NULL,"mediatek,rf_clock_buffer");
+ if(node) {
+ of_property_read_u32(node,"buffer1",(u32 *)&CLK_BUF1_STATUS);
+ of_property_read_u32(node,"buffer2",(u32 *)&CLK_BUF2_STATUS);
+ of_property_read_u32(node,"buffer3",(u32 *)&CLK_BUF3_STATUS);
+ of_property_read_u32(node,"buffer4",(u32 *)&CLK_BUF4_STATUS);
+ }
+ else {
+ CCCI_INF_MSG(md->index, RPC, "%s can't find compatible node\n", __func__);
+ }
+#endif
+ clkbuf->CLKBuf_Count = CLKBUF_MAX_COUNT;
+ clkbuf->CLKBuf_Status[0] = CLK_BUF1_STATUS;
+ clkbuf->CLKBuf_Status[1] = CLK_BUF2_STATUS;
+ clkbuf->CLKBuf_Status[2] = CLK_BUF3_STATUS;
+ clkbuf->CLKBuf_Status[3] = CLK_BUF4_STATUS;
+ clk_buf_get_swctrl_status(swctrl_status);
+ clkbuf->CLKBuf_SWCtrl_Status[0] = swctrl_status[0];
+ clkbuf->CLKBuf_SWCtrl_Status[1] = swctrl_status[1];
+ clkbuf->CLKBuf_SWCtrl_Status[2] = swctrl_status[2];
+ clkbuf->CLKBuf_SWCtrl_Status[3] = swctrl_status[3];
+ }
+ CCCI_INF_MSG(md->index, RPC, "IPC_RPC_GET_RF_CLK_BUF count=%x\n", clkbuf->CLKBuf_Count);
+ break;
+ }
+#endif
+ case IPC_RPC_GET_GPIO_VAL_OP:
+ case IPC_RPC_GET_ADC_VAL_OP:
+ {
+ unsigned int num = 0;
+ int val = 0;
+
+ if(pkt_num != 1) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d!\n",
+ p_rpc_buf->op_id, pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ goto err4;
+ }
+
+ num = *(unsigned int*)(pkt[0].buf);
+ if(p_rpc_buf->op_id == IPC_RPC_GET_GPIO_VAL_OP) {
+ val = get_md_gpio_val(num);
+ } else if (p_rpc_buf->op_id == IPC_RPC_GET_ADC_VAL_OP) {
+ val = get_md_adc_val(num);
+ }
+ tmp_data[0] = val;
+ CCCI_INF_MSG(md->index, RPC, "[0x%X]: num=%d, val=%d!\n", p_rpc_buf->op_id, num, val);
+
+err4:
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+
+ case IPC_RPC_GET_GPIO_ADC_OP:
+ {
+ int num;
+ unsigned int val, i;
+ struct ccci_rpc_gpio_adc_intput *input;
+ struct ccci_rpc_gpio_adc_output *output;
+
+ if(pkt_num != 1) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d!\n",
+ p_rpc_buf->op_id, pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+ input = (struct ccci_rpc_gpio_adc_intput *)(pkt[0].buf);
+ pkt_num = 0;
+ tmp_data[0] = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(struct ccci_rpc_gpio_adc_output);
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ output = (struct ccci_rpc_gpio_adc_output*) &tmp_data[1];
+ memset(output, 0xF, sizeof(struct ccci_rpc_gpio_adc_output)); // 0xF for failure
+ CCCI_INF_MSG(md->index, KERN, "IPC_RPC_GET_GPIO_ADC_OP request=%x\n", input->reqMask);
+ if((input->reqMask&(RPC_REQ_GPIO_PIN|RPC_REQ_GPIO_VALUE)) == (RPC_REQ_GPIO_PIN|RPC_REQ_GPIO_VALUE)) {
+ for(i=0; i<GPIO_MAX_COUNT; i++) {
+ if(input->gpioValidPinMask & (1<<i)) {
+ if((num = get_md_gpio_info(input->gpioPinName[i], strlen(input->gpioPinName[i]))) >= 0) {
+ output->gpioPinNum[i] = num;
+ val = get_md_gpio_val(num);
+ output->gpioPinValue[i] = val;
+ }
+ }
+ }
+ } else {
+ if(input->reqMask & RPC_REQ_GPIO_PIN) {
+ for(i=0; i<GPIO_MAX_COUNT; i++) {
+ if(input->gpioValidPinMask & (1<<i)) {
+ if((num = get_md_gpio_info(input->gpioPinName[i], strlen(input->gpioPinName[i]))) >= 0) {
+ output->gpioPinNum[i] = num;
+ }
+ }
+ }
+ }
+ if(input->reqMask & RPC_REQ_GPIO_VALUE) {
+ for(i=0; i<GPIO_MAX_COUNT; i++) {
+ if(input->gpioValidPinMask & (1<<i)) {
+ val = get_md_gpio_val(input->gpioPinNum[i]);
+ output->gpioPinValue[i] = val;
+ }
+ }
+ }
+ }
+ if((input->reqMask&(RPC_REQ_ADC_PIN|RPC_REQ_ADC_VALUE)) == (RPC_REQ_ADC_PIN|RPC_REQ_ADC_VALUE)) {
+ if((num = get_md_adc_info(input->adcChName, strlen(input->adcChName))) >= 0) {
+ output->adcChNum = num;
+ output->adcChMeasSum = 0;
+ for(i=0; i<input->adcChMeasCount; i++) {
+ val = get_md_adc_val(num);
+ output->adcChMeasSum += val;
+ }
+ }
+ } else {
+ if(input->reqMask & RPC_REQ_ADC_PIN) {
+ if((num = get_md_adc_info(input->adcChName, strlen(input->adcChName))) >= 0) {
+ output->adcChNum = num;
+ }
+ }
+ if(input->reqMask & RPC_REQ_ADC_VALUE) {
+ output->adcChMeasSum = 0;
+ for(i=0; i<input->adcChMeasCount; i++) {
+ val = get_md_adc_val(input->adcChNum);
+ output->adcChMeasSum += val;
+ }
+ }
+ }
+ break;
+ }
+
+ case IPC_RPC_DSP_EMI_MPU_SETTING:
+ {
+ struct ccci_rpc_dsp_emi_mpu_input *input, *output;
+
+ if(pkt_num != 1) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid parameter for [0x%X]: pkt_num=%d!\n",
+ p_rpc_buf->op_id, pkt_num);
+ tmp_data[0] = FS_PARAM_ERROR;
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+ input = (struct ccci_rpc_dsp_emi_mpu_input *)(pkt[0].buf);
+ pkt_num = 0;
+ tmp_data[0] = 0;
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ pkt[pkt_num].len = sizeof(struct ccci_rpc_dsp_emi_mpu_input);
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ output = (struct ccci_rpc_dsp_emi_mpu_input *) &tmp_data[1];
+ output->request = 0;
+ CCCI_INF_MSG(md->index, KERN, "IPC_RPC_DSP_EMI_MPU_SETTING request=%x\n", input->request);
+ if(md->mem_layout.dsp_region_phy != 0)
+ ccci_set_dsp_region_protection(md, 1);
+ break;
+ }
+
+ case IPC_RPC_IT_OP:
+ {
+ int i;
+ CCCI_INF_MSG(md->index, RPC, "[RPCIT] enter IT operation in ccci_rpc_work\n");
+ //exam input parameters in pkt
+ for(i=0; i<pkt_num ; i++){
+ CCCI_INF_MSG(md->index, RPC, "len=%d val=%X\n", pkt[i].len, *((unsigned int *)pkt[i].buf));
+ }
+ tmp_data[0] = 1;
+ tmp_data[1] = 0xA5A5;
+ pkt_num = 0;
+ CCCI_INF_MSG(md->index, RPC,"[RPCIT] prepare output parameters\n");
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ CCCI_INF_MSG(md->index, RPC,"[RPCIT] LV[%d] len= 0x%08X, value= 0x%08X\n", 0, pkt[0].len, *((unsigned int *)pkt[0].buf));
+ pkt[pkt_num].len = sizeof(unsigned int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[1];
+ CCCI_INF_MSG(md->index, RPC,"[RPCIT] LV[%d] len= 0x%08X, value= 0x%08X\n", 1, pkt[1].len, *((unsigned int *)pkt[1].buf));
+ break;
+ }
+
+ default:
+ CCCI_INF_MSG(md->index, RPC, "[Error]Unknown Operation ID (0x%08X)\n", p_rpc_buf->op_id);
+ tmp_data[0] = FS_NO_OP;
+ pkt_num = 0;
+ pkt[pkt_num].len = sizeof(int);
+ pkt[pkt_num++].buf = (void*) &tmp_data[0];
+ break;
+ }
+
+ p_rpc_buf->para_num = pkt_num;
+ CCCI_DBG_MSG(md->index, RPC, "ccci_rpc_work_helper-- %d\n", p_rpc_buf->para_num);
+}
+
+
+static void rpc_msg_handler(struct ccci_port *port, struct ccci_request *req)
+{
+ struct ccci_modem *md = port->modem;
+ struct rpc_buffer *rpc_buf = (struct rpc_buffer *)req->skb->data;
+ int i, data_len=0, AlignLength, ret;
+ struct rpc_pkt pkt[RPC_MAX_ARG_NUM];
+ char *ptr, *ptr_base;
+ unsigned int tmp_data[64]; // size of tmp_data should be >= any RPC output result
+
+ // sanity check
+ if(rpc_buf->header.reserved<0 || rpc_buf->header.reserved>RPC_REQ_BUFFER_NUM ||
+ rpc_buf->para_num<0 || rpc_buf->para_num>RPC_MAX_ARG_NUM) {
+ CCCI_ERR_MSG(md->index, RPC, "invalid RPC index %d/%d\n", rpc_buf->header.reserved, rpc_buf->para_num);
+ goto err_out;
+ }
+ // parse buffer
+ ptr_base = ptr = rpc_buf->buffer;
+ for(i=0; i<rpc_buf->para_num; i++) {
+ pkt[i].len = *((unsigned int*)ptr);
+ ptr += sizeof(pkt[i].len);
+ pkt[i].buf = ptr;
+ ptr += ((pkt[i].len+3)>>2)<<2; // 4byte align
+ }
+ if((ptr-ptr_base) > RPC_MAX_BUF_SIZE) {
+ CCCI_ERR_MSG(md->index, RPC, "RPC overflow in parse 0x%p\n", (void*)(ptr-ptr_base));
+ goto err_out;
+ }
+ // handle RPC request
+ ccci_rpc_work_helper(md, pkt, rpc_buf, tmp_data);
+ // write back to modem
+ // update message
+ rpc_buf->op_id |= RPC_API_RESP_ID;
+ data_len += (sizeof(rpc_buf->op_id) + sizeof(rpc_buf->para_num));
+ ptr = rpc_buf->buffer;
+ for(i=0; i<rpc_buf->para_num; i++) {
+ if((data_len + sizeof(pkt[i].len) + pkt[i].len) > RPC_MAX_BUF_SIZE) {
+ CCCI_ERR_MSG(md->index, RPC, "RPC overflow in write %zu\n", data_len + sizeof(pkt[i].len)+ pkt[i].len);
+ goto err_out;
+ }
+
+ *((unsigned int*)ptr) = pkt[i].len;
+ ptr += sizeof(pkt[i].len);
+ data_len += sizeof(pkt[i].len);
+
+ AlignLength = ((pkt[i].len+3)>>2)<<2; // 4byte aligned
+ data_len += AlignLength;
+
+ if(ptr != pkt[i].buf)
+ memcpy(ptr, pkt[i].buf, pkt[i].len);
+ else
+ CCCI_DBG_MSG(md->index, RPC, "same addr, no copy, op_id=0x%x\n", rpc_buf->op_id);
+
+ ptr += AlignLength;
+ }
+ // resize skb
+ data_len += sizeof(struct ccci_header);
+ if(data_len > req->skb->len)
+ skb_put(req->skb, data_len - req->skb->len);
+ else if(data_len < req->skb->len)
+ skb_trim(req->skb, data_len);
+ // update CCCI header
+ rpc_buf->header.channel = CCCI_RPC_TX;
+ rpc_buf->header.data[1] = data_len;
+ CCCI_DBG_MSG(md->index, RPC, "Write %d/%d, %08X, %08X, %08X, %08X, op_id=0x%x\n", req->skb->len, data_len,
+ rpc_buf->header.data[0], rpc_buf->header.data[1], rpc_buf->header.channel, rpc_buf->header.reserved, rpc_buf->op_id);
+ // switch to Tx request
+ req->policy = RECYCLE;
+ req->blocking = 1;
+ ret = ccci_port_send_request(port, req);
+ if(ret)
+ goto err_out;
+ return;
+
+err_out:
+ req->policy = RECYCLE;
+ ccci_free_req(req);
+ return;
+}
+int process_rpc_kernel_msg(struct ccci_port *port, struct ccci_request *req)
+{
+ struct ccci_modem *md = port->modem;
+ struct rpc_buffer *rpc_buf = (struct rpc_buffer *)req->skb->data;
+ switch(rpc_buf->op_id){
+#ifdef CONFIG_MTK_TC1_FEATURE
+ // LGE specific OP ID
+ case RPC_CCCI_LGE_FAC_READ_SIM_LOCK_TYPE:
+ case RPC_CCCI_LGE_FAC_READ_FUSG_FLAG:
+ case RPC_CCCI_LGE_FAC_CHECK_UNLOCK_CODE_VALIDNESS:
+ case RPC_CCCI_LGE_FAC_CHECK_NETWORK_CODE_VALIDNESS:
+ case RPC_CCCI_LGE_FAC_WRITE_SIM_LOCK_TYPE:
+ case RPC_CCCI_LGE_FAC_READ_IMEI:
+ case RPC_CCCI_LGE_FAC_WRITE_IMEI:
+ case RPC_CCCI_LGE_FAC_READ_NETWORK_CODE_LIST_NUM:
+ case RPC_CCCI_LGE_FAC_READ_NETWORK_CODE:
+ case RPC_CCCI_LGE_FAC_WRITE_NETWORK_CODE_LIST_NUM:
+ case RPC_CCCI_LGE_FAC_WRITE_UNLOCK_CODE_VERIFY_FAIL_COUNT:
+ case RPC_CCCI_LGE_FAC_READ_UNLOCK_CODE_VERIFY_FAIL_COUNT:
+ case RPC_CCCI_LGE_FAC_WRITE_UNLOCK_FAIL_COUNT:
+ case RPC_CCCI_LGE_FAC_READ_UNLOCK_FAIL_COUNT:
+ case RPC_CCCI_LGE_FAC_WRITE_UNLOCK_CODE:
+ case RPC_CCCI_LGE_FAC_VERIFY_UNLOCK_CODE:
+ case RPC_CCCI_LGE_FAC_WRITE_NETWORK_CODE:
+ case RPC_CCCI_LGE_FAC_INIT_SIM_LOCK_DATA:
+ CCCI_INF_MSG(port->modem->index, KERN, "userspace rpc msg 0x%x\n", rpc_buf->op_id);
+ return 0;
+#endif
+ default:
+ CCCI_INF_MSG(port->modem->index, KERN, "kernelspace rpc msg 0x%x\n", rpc_buf->op_id);
+ list_del(&req->entry);
+ rpc_msg_handler(port,req);
+ CCCI_INF_MSG(port->modem->index, KERN, "kernelspace rpc msg done\n");
+ return 1;
+ }
+}
+static void status_msg_handler(struct ccci_port *port, struct ccci_request *req)
+{
+ struct ccci_modem *md = port->modem;
+ struct ccci_header *ccci_h = (struct ccci_header *)req->skb->data;
+
+ del_timer(&port->modem->md_status_timeout);
+ CCCI_INF_MSG(port->modem->index, KERN, "modem status info seq=0x%X\n", *(((u32 *)ccci_h)+2));
+ ccci_cmpt_mem_dump(md->index, req->skb->data, req->skb->len);
+ req->policy = RECYCLE;
+ ccci_free_req(req);
+ if(port->modem->md_state == READY)
+ mod_timer(&port->modem->md_status_poller, jiffies+15*HZ);
+}
+
+void md_status_poller_func(unsigned long data)
+{
+ struct ccci_modem *md = (struct ccci_modem *)data;
+ int ret;
+
+ mod_timer(&md->md_status_timeout, jiffies+5*HZ);
+ ret = ccci_send_msg_to_md(md, CCCI_STATUS_TX, 0, 0, 0);
+ CCCI_INF_MSG(md->index, KERN, "poll modem status %d seq=0x%X\n", ret, md->seq_nums[OUT][CCCI_STATUS_TX]);
+
+ if(ret) {
+ CCCI_ERR_MSG(md->index, KERN, "fail to send modem status polling msg ret=%d\n", ret);
+ del_timer(&md->md_status_timeout);
+ if(ret==-EBUSY && md->md_state==READY) {
+ if(md->md_status_poller_flag & MD_STATUS_POLL_BUSY) {
+ md->ops->dump_info(md, DUMP_FLAG_CLDMA, NULL, 0);
+ ccci_md_exception_notify(md, MD_NO_RESPONSE);
+ } else {
+ md->md_status_poller_flag |= MD_STATUS_POLL_BUSY;
+ mod_timer(&md->md_status_poller, jiffies+10*HZ);
+ }
+}
+ } else {
+ md->md_status_poller_flag &= ~MD_STATUS_POLL_BUSY;
+ }
+}
+
+void md_status_timeout_func(unsigned long data)
+{
+ struct ccci_modem *md = (struct ccci_modem *)data;
+ if(md->md_status_poller_flag & MD_STATUS_ASSERTED) {
+ CCCI_ERR_MSG(md->index, KERN, "modem status polling timeout, assert fail\n");
+ md->ops->dump_info(md, DUMP_FLAG_CLDMA, NULL, 0);
+ ccci_md_exception_notify(md, MD_NO_RESPONSE);
+ } else {
+ CCCI_ERR_MSG(md->index, KERN, "modem status polling timeout, force assert\n");
+ md->md_status_poller_flag |= MD_STATUS_ASSERTED;
+ md->ops->dump_info(md, DUMP_FLAG_DUMP_QUEUE_0, NULL, 0);
+ mod_timer(&md->md_status_timeout, jiffies+5*HZ);
+ md->ops->force_assert(md, CCIF_INTR_SEQ);
+ }
+}
+
+static int port_kernel_thread(void *arg)
+{
+ struct ccci_port *port = arg;
+ //struct sched_param param = { .sched_priority = 1 };
+ struct ccci_request *req;
+ struct ccci_header *ccci_h;
+ unsigned long flags;
+ int ret;
+
+ CCCI_DBG_MSG(port->modem->index, KERN, "port %s's thread runnning\n", port->name);
+ //sched_setscheduler(current, SCHED_FIFO, &param);
+
+ while(1) {
+ if(list_empty(&port->rx_req_list)) {
+ ret = wait_event_interruptible(port->rx_wq, !list_empty(&port->rx_req_list));
+ if(ret == -ERESTARTSYS) {
+ continue; // FIXME
+ }
+ }
+ if (kthread_should_stop()){
+ break ;
+ }
+ CCCI_DBG_MSG(port->modem->index, KERN, "read on %s\n", port->name);
+ // 1. dequeue
+ spin_lock_irqsave(&port->rx_req_lock, flags);
+ req = list_first_entry(&port->rx_req_list, struct ccci_request, entry);
+ list_del(&req->entry);
+ if(--(port->rx_length) == 0)
+ ccci_port_ask_more_request(port);
+ spin_unlock_irqrestore(&port->rx_req_lock, flags);
+ // 2. process the request
+ ccci_h = (struct ccci_header *)req->skb->data;
+ switch(ccci_h->channel){ // for a certain thread, only one kind of message is handled
+ case CCCI_CONTROL_RX:
+ control_msg_handler(port, req);
+ break;
+ case CCCI_SYSTEM_RX:
+ system_msg_handler(port, req);
+ break;
+ case CCCI_STATUS_RX:
+ status_msg_handler(port, req);
+ break;
+ };
+ // ATTENTION, message handler will free request, do NOT reference request any more
+ }
+ return 0;
+}
+
+static int port_kernel_init(struct ccci_port *port)
+{
+ CCCI_DBG_MSG(port->modem->index, KERN, "kernel port %s is initializing\n", port->name);
+ port->private_data = kthread_run(port_kernel_thread, port, "%s", port->name);
+ port->rx_length_th = MAX_QUEUE_LENGTH;
+ return 0;
+}
+
+static int port_kernel_recv_req(struct ccci_port *port, struct ccci_request *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->rx_req_lock, flags);
+ CCCI_DBG_MSG(port->modem->index, IPC, "recv on %s, len=%d\n", port->name, port->rx_length);
+ if(port->rx_length < port->rx_length_th) {
+ port->flags &= ~PORT_F_RX_FULLED;
+ port->rx_length++;
+ list_del(&req->entry); // dequeue from queue's list
+ list_add_tail(&req->entry, &port->rx_req_list);
+ spin_unlock_irqrestore(&port->rx_req_lock, flags);
+ wake_lock_timeout(&port->rx_wakelock, HZ);
+ wake_up_all(&port->rx_wq);
+ return 0;
+ } else {
+ port->flags |= PORT_F_RX_FULLED;
+ spin_unlock_irqrestore(&port->rx_req_lock, flags);
+ if(port->flags & PORT_F_ALLOW_DROP/* || !(port->flags&PORT_F_RX_EXCLUSIVE)*/) {
+ CCCI_INF_MSG(port->modem->index, IPC, "port %s Rx full, drop packet\n", port->name);
+ goto drop;
+ } else {
+ return -CCCI_ERR_PORT_RX_FULL;
+ }
+ }
+
+drop:
+ // drop this packet
+ CCCI_INF_MSG(port->modem->index, IPC, "drop on %s, len=%d\n", port->name, port->rx_length);
+ list_del(&req->entry);
+ req->policy = RECYCLE;
+ ccci_free_req(req);
+ return -CCCI_ERR_DROP_PACKET;
+}
+
+static void port_kernel_md_state_notice(struct ccci_port *port, MD_STATE state)
+{
+ if(port->rx_ch != CCCI_CONTROL_RX)
+ return;
+
+ // only for thoes states which are updated by modem driver
+ switch(state) {
+ case RESET:
+ del_timer(&port->modem->md_status_poller);
+ del_timer(&port->modem->md_status_timeout);
+
+ del_timer(&port->modem->ex_monitor);
+ del_timer(&port->modem->ex_monitor2);
+
+ port->modem->md_status_poller_flag = 0;
+ break;
+ default:
+ break;
+ };
+}
+
+struct ccci_port_ops kernel_port_ops = {
+ .init = &port_kernel_init,
+ .recv_request = &port_kernel_recv_req,
+ .md_state_notice = &port_kernel_md_state_notice,
+};
+
+void ccci_md_exception_notify(struct ccci_modem *md, MD_EX_STAGE stage)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&md->ctrl_lock, flags);
+ CCCI_INF_MSG(md->index, KERN, "MD exception logical %d->%d\n", md->ex_stage, stage);
+ md->ex_stage = stage;
+ switch(md->ex_stage) {
+ case EX_INIT:
+ del_timer(&md->ex_monitor2);
+ del_timer(&md->bootup_timer);
+ del_timer(&md->md_status_poller);
+ del_timer(&md->md_status_timeout);
+ md->ee_info_flag |= ((1<<MD_EE_FLOW_START)|(1<<MD_EE_SWINT_GET));
+ if(!MD_IN_DEBUG(md))
+ mod_timer(&md->ex_monitor,jiffies+EX_TIMER_SWINT*HZ);
+ md->ops->broadcast_state(md, EXCEPTION);
+ break;
+ case EX_DHL_DL_RDY:
+ break;
+ case EX_INIT_DONE:
+ ccci_reset_seq_num(md);
+ break;
+ case MD_NO_RESPONSE:
+ // don't broadcast exception state, only dump
+ del_timer(&md->md_status_timeout);
+ CCCI_ERR_MSG(md->index, KERN, "MD long time no response, flag=%x\n", md->md_status_poller_flag);
+ md->ee_info_flag |= ((1<<MD_EE_FLOW_START)|(1<<MD_EE_PENDING_TOO_LONG)|(1<<MD_STATE_UPDATE));
+ mod_timer(&md->ex_monitor,jiffies);
+ break;
+ case MD_WDT:
+ del_timer(&md->md_status_poller);
+ del_timer(&md->md_status_timeout);
+
+ md->ee_info_flag |= ((1<<MD_EE_FLOW_START)|(1<<MD_EE_WDT_GET)|(1<<MD_STATE_UPDATE));
+ mod_timer(&md->ex_monitor,jiffies);
+ break;
+ default:
+ break;
+ };
+ spin_unlock_irqrestore(&md->ctrl_lock, flags);
+}
+EXPORT_SYMBOL(ccci_md_exception_notify);
+
+static void ccci_aed(struct ccci_modem *md, unsigned int dump_flag, char *aed_str, int db_opt)
+{
+ void *ex_log_addr = NULL;
+ int ex_log_len = 0;
+ void *md_img_addr = NULL;
+ int md_img_len = 0;
+ int info_str_len = 0;
+ char buff[AED_STR_LEN];
+ char *img_inf;
+
+ img_inf = ccci_get_md_info_str(md->index);
+ if(img_inf == NULL)
+ img_inf = "";
+ info_str_len = strlen(aed_str);
+ info_str_len += strlen(img_inf);
+
+ if(info_str_len > AED_STR_LEN){
+ buff[AED_STR_LEN-1] = '\0'; // Cut string length to AED_STR_LEN
+ }
+
+ snprintf(buff, AED_STR_LEN, "md%d:%s%s", md->index+1, aed_str, img_inf); // MD ID must sync with aee_dump_ccci_debug_info()
+
+ if(dump_flag & CCCI_AED_DUMP_CCIF_REG) { // check this first, as we overwrite share memory here
+ ex_log_addr = md->smem_layout.ccci_exp_smem_mdss_debug_vir;
+ ex_log_len = md->smem_layout.ccci_exp_smem_mdss_debug_size;
+ md->ops->dump_info(md, DUMP_FLAG_CCIF|DUMP_FLAG_CCIF_REG, md->smem_layout.ccci_exp_smem_base_vir+CCCI_SMEM_OFFSET_CCIF_SRAM, CCCC_SMEM_CCIF_SRAM_SIZE);
+ }
+ if(dump_flag & CCCI_AED_DUMP_EX_MEM) {
+ ex_log_addr = md->smem_layout.ccci_exp_smem_mdss_debug_vir;
+ ex_log_len = md->smem_layout.ccci_exp_smem_mdss_debug_size;
+ }
+ if(dump_flag & CCCI_AED_DUMP_EX_PKT) {
+ ex_log_addr = (void *)&md->ex_info;
+ ex_log_len = sizeof(EX_LOG_T);
+ }
+ if(dump_flag & CCCI_AED_DUMP_MD_IMG_MEM) {
+ md_img_addr = (void *)md->mem_layout.md_region_vir;
+ md_img_len = MD_IMG_DUMP_SIZE;
+ }
+
+#if defined (CONFIG_MTK_AEE_FEATURE)
+ aed_md_exception_api(ex_log_addr, ex_log_len, md_img_addr, md_img_len, buff, db_opt);
+#endif
+}
+
+static void ccci_ee_info_dump(struct ccci_modem *md)
+{
+ char ex_info[EE_BUF_LEN]=""; // attention, be careful with string length!
+ char i_bit_ex_info[EE_BUF_LEN]="\n[Others] May I-Bit dis too long\n";
+ int db_opt = (DB_OPT_DEFAULT|DB_OPT_FTRACE);
+ int dump_flag = 0;
+ DEBUG_INFO_T *debug_info = &md->debug_info;
+ unsigned char c;
+
+ struct rtc_time tm;
+ struct timeval tv = {0};
+ struct timeval tv_android = {0};
+ struct rtc_time tm_android;
+
+ do_gettimeofday(&tv);
+ tv_android = tv;
+ rtc_time_to_tm(tv.tv_sec, &tm);
+ tv_android.tv_sec -= sys_tz.tz_minuteswest*60;
+ rtc_time_to_tm(tv_android.tv_sec, &tm_android);
+ CCCI_INF_MSG(md->index, KERN, "Sync:%d%02d%02d %02d:%02d:%02d.%u(%02d:%02d:%02d.%03d(TZone))\n",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec,
+ (unsigned int) tv.tv_usec,
+ tm_android.tm_hour, tm_android.tm_min, tm_android.tm_sec,
+ (unsigned int) tv_android.tv_usec);
+
+ CCCI_INF_MSG(md->index, KERN, "exception type(%d):%s\n",debug_info->type,debug_info->name?:"Unknown");
+
+ switch(debug_info->type)
+ {
+ case MD_EX_TYPE_ASSERT_DUMP:
+ case MD_EX_TYPE_ASSERT:
+ CCCI_INF_MSG(md->index, KERN, "filename = %s\n", debug_info->assert.file_name);
+ CCCI_INF_MSG(md->index, KERN, "line = %d\n", debug_info->assert.line_num);
+ CCCI_INF_MSG(md->index, KERN, "para0 = %d, para1 = %d, para2 = %d\n",
+ debug_info->assert.parameters[0],
+ debug_info->assert.parameters[1],
+ debug_info->assert.parameters[2]);
+ snprintf(ex_info,EE_BUF_LEN,"\n[%s] file:%s line:%d\np1:0x%08x\np2:0x%08x\np3:0x%08x\n",
+ debug_info->name,
+ debug_info->assert.file_name,
+ debug_info->assert.line_num,
+ debug_info->assert.parameters[0],
+ debug_info->assert.parameters[1],
+ debug_info->assert.parameters[2]);
+ break;
+ case MD_EX_TYPE_UNDEF:
+ case MD_EX_TYPE_SWI:
+ case MD_EX_TYPE_PREF_ABT:
+ case MD_EX_TYPE_DATA_ABT:
+ case MD_EX_TYPE_FATALERR_BUF:
+ case MD_EX_TYPE_FATALERR_TASK:
+ case MD_EX_TYPE_C2K_ERROR:
+ CCCI_INF_MSG(md->index, KERN, "fatal error code 1 = %d\n", debug_info->fatal_error.err_code1);
+ CCCI_INF_MSG(md->index, KERN, "fatal error code 2 = %d\n", debug_info->fatal_error.err_code2);
+ CCCI_INF_MSG(md->index, KERN, "fatal error offender %s\n", debug_info->fatal_error.offender);
+ if(debug_info->fatal_error.offender[0] != '\0') {
+ snprintf(ex_info,EE_BUF_LEN,"\n[%s] err_code1:%d err_code2:%d\nMD Offender:%s\n", debug_info->name,
+ debug_info->fatal_error.err_code1, debug_info->fatal_error.err_code2,
+ debug_info->fatal_error.offender);
+ } else {
+ snprintf(ex_info,EE_BUF_LEN,"\n[%s] err_code1:%d err_code2:%d\n", debug_info->name,
+ debug_info->fatal_error.err_code1, debug_info->fatal_error.err_code2);
+ }
+ break;
+ case MD_EX_TYPE_EMI_CHECK:
+ CCCI_INF_MSG(md->index, KERN, "md_emi_check: %08X, %08X, %02d, %08X\n",
+ debug_info->data.data0, debug_info->data.data1,
+ debug_info->data.channel, debug_info->data.reserved);
+ snprintf(ex_info,EE_BUF_LEN,"\n[emi_chk] %08X, %08X, %02d, %08X\n",
+ debug_info->data.data0, debug_info->data.data1,
+ debug_info->data.channel, debug_info->data.reserved);
+ break;
+ case DSP_EX_TYPE_ASSERT:
+ CCCI_INF_MSG(md->index, KERN, "filename = %s\n", debug_info->dsp_assert.file_name);
+ CCCI_INF_MSG(md->index, KERN, "line = %d\n", debug_info->dsp_assert.line_num);
+ CCCI_INF_MSG(md->index, KERN, "exec unit = %s\n", debug_info->dsp_assert.execution_unit);
+ CCCI_INF_MSG(md->index, KERN, "para0 = %d, para1 = %d, para2 = %d\n",
+ debug_info->dsp_assert.parameters[0],
+ debug_info->dsp_assert.parameters[1],
+ debug_info->dsp_assert.parameters[2]);
+ snprintf(ex_info,EE_BUF_LEN,"\n[%s] file:%s line:%d\nexec:%s\np1:%d\np2:%d\np3:%d\n",
+ debug_info->name, debug_info->assert.file_name, debug_info->assert.line_num,
+ debug_info->dsp_assert.execution_unit,
+ debug_info->dsp_assert.parameters[0],
+ debug_info->dsp_assert.parameters[1],
+ debug_info->dsp_assert.parameters[2]);
+ break;
+ case DSP_EX_TYPE_EXCEPTION:
+ CCCI_INF_MSG(md->index, KERN, "exec unit = %s, code1:0x%08x\n", debug_info->dsp_exception.execution_unit,
+ debug_info->dsp_exception.code1);
+ snprintf(ex_info,EE_BUF_LEN,"\n[%s] exec:%s code1:0x%08x\n",
+ debug_info->name, debug_info->dsp_exception.execution_unit,
+ debug_info->dsp_exception.code1);
+ break;
+ case DSP_EX_FATAL_ERROR:
+ CCCI_INF_MSG(md->index, KERN, "exec unit = %s\n", debug_info->dsp_fatal_err.execution_unit);
+ CCCI_INF_MSG(md->index, KERN, "err_code0 = 0x%08x, err_code1 = 0x%08x\n",
+ debug_info->dsp_fatal_err.err_code[0],
+ debug_info->dsp_fatal_err.err_code[1]);
+
+ snprintf(ex_info,EE_BUF_LEN,"\n[%s] exec:%s err_code1:0x%08x err_code2:0x%08x\n",
+ debug_info->name, debug_info->dsp_fatal_err.execution_unit,
+ debug_info->dsp_fatal_err.err_code[0],
+ debug_info->dsp_fatal_err.err_code[1]);
+ break;
+
+ default: // Only display exception name
+ snprintf(ex_info,EE_BUF_LEN,"\n[%s]\n", debug_info->name);
+ break;
+ }
+
+ // Add additional info
+ switch(debug_info->more_info) {
+ case MD_EE_CASE_ONLY_SWINT:
+ strcat(ex_info, "\nOnly SWINT case\n");
+ break;
+ case MD_EE_CASE_SWINT_MISSING:
+ strcat(ex_info, "\nSWINT missing case\n");
+ break;
+ case MD_EE_CASE_ONLY_EX:
+ strcat(ex_info, "\nOnly EX case\n");
+ break;
+ case MD_EE_CASE_ONLY_EX_OK:
+ strcat(ex_info, "\nOnly EX_OK case\n");
+ break;
+ case MD_EE_CASE_AP_MASK_I_BIT_TOO_LONG:
+ strcat(i_bit_ex_info, ex_info);
+ strcpy(ex_info, i_bit_ex_info);
+ break;
+ case MD_EE_CASE_TX_TRG:
+ case MD_EE_CASE_ISR_TRG:
+ strcat(ex_info, "\n[Others] May I-Bit dis too long\n");
+ break;
+ case MD_EE_CASE_NO_RESPONSE:
+ // use strcpy, otherwise if this happens after a MD EE, the former EE info will be printed out
+ strcpy(ex_info, "\n[Others] MD long time no response\n");
+ db_opt |= DB_OPT_FTRACE;
+ break;
+ case MD_EE_CASE_WDT:
+ strcpy(ex_info, "\n[Others] MD watchdog timeout interrupt\n");
+ break;
+ default:
+ break;
+ }
+
+ // get ELM_status field from MD side
+ c = md->ex_info.envinfo.ELM_status;
+ CCCI_INF_MSG(md->index, KERN, "ELM_status: %x\n", c);
+ switch (c)
+ {
+ case 0xFF:
+ strcat(ex_info, "\nno ELM info\n");
+ break;
+ case 0xAE:
+ strcat(ex_info, "\nELM rlat:FAIL\n");
+ break;
+ case 0xBE:
+ strcat(ex_info, "\nELM wlat:FAIL\n");
+ break;
+ case 0xDE:
+ strcat(ex_info, "\nELM r/wlat:PASS\n");
+ break;
+ default:
+ break;
+ }
+
+ // Dump MD EE info
+ CCCI_INF_MSG(md->index, KERN, "Dump MD EX log\n");
+ if(debug_info->more_info == MD_EE_CASE_NORMAL &&
+ md->boot_stage == MD_BOOT_STAGE_0) {
+ ccci_mem_dump(md->index, &md->ex_info, sizeof(EX_LOG_T));
+ } else {
+ ccci_mem_dump(md->index, md->smem_layout.ccci_exp_smem_base_vir, md->smem_layout.ccci_exp_dump_size);
+ }
+ // Dump MD image memory
+ CCCI_INF_MSG(md->index, KERN, "Dump MD image memory\n");
+ ccci_mem_dump(md->index, (void *)md->mem_layout.md_region_vir, MD_IMG_DUMP_SIZE);
+ // Dump MD memory layout
+ CCCI_INF_MSG(md->index, KERN, "Dump MD layout struct\n");
+ ccci_mem_dump(md->index, &md->mem_layout, sizeof(struct ccci_mem_layout));
+ // Dump MD register
+ md->ops->dump_info(md, DUMP_FLAG_REG, NULL, 0);
+
+ if(debug_info->more_info == MD_EE_CASE_NORMAL &&
+ md->boot_stage == MD_BOOT_STAGE_0) { // MD will not fill in share memory before we send runtime data
+ dump_flag = CCCI_AED_DUMP_EX_PKT;
+ } else { // otherwise always dump whole share memory, as MD will fill debug log into its 2nd 1K region after bootup
+ dump_flag = CCCI_AED_DUMP_EX_MEM;
+ if(debug_info->more_info == MD_EE_CASE_NO_RESPONSE)
+ dump_flag |= CCCI_AED_DUMP_CCIF_REG;
+ }
+ md->boot_stage = MD_BOOT_STAGE_EXCEPTION; // update here to maintain handshake stage info druing exception handling
+ if(debug_info->type == MD_EX_TYPE_C2K_ERROR && debug_info->fatal_error.err_code1 == MD_EX_C2K_FATAL_ERROR){
+ CCCI_INF_MSG(md->index, KERN, "C2K EE, No need trigger DB\n");
+ }else{
+ ccci_aed(md, dump_flag, ex_info, db_opt);
+ }
+ if(debug_info->more_info == MD_EE_CASE_ONLY_SWINT) {
+ md->ops->dump_info(md, DUMP_FLAG_DUMP_QUEUE_0|DUMP_FLAG_CCIF|DUMP_FLAG_CCIF_REG, NULL, 0);
+ }
+ if(*((int *)(md->mem_layout.smem_region_vir+CCCI_SMEM_OFFSET_SEQERR)) != 0) {
+ CCCI_INF_MSG(md->index, KERN, "MD found wrong sequence number\n");
+ md->ops->dump_info(md, DUMP_FLAG_CLDMA, NULL, 0);
+ }
+}
+
+/*
+ * copy raw data (EX_LOG_T) received from modem into CCCI's DEBUG_INFO_T
+ */
+static void ccci_md_exception(struct ccci_modem *md)
+{
+ EX_LOG_T *ex_info;
+ int ee_type, ee_case;
+ DEBUG_INFO_T *debug_info = &md->debug_info;
+
+ if(debug_info == NULL) {
+ return;
+ }
+
+ if(debug_info->more_info==MD_EE_CASE_NORMAL &&
+ md->boot_stage == MD_BOOT_STAGE_0) {
+ ex_info = &md->ex_info;
+ } else {
+ ex_info = (EX_LOG_T *)md->smem_layout.ccci_exp_rec_base_vir;
+ }
+ ee_case = debug_info->more_info;
+
+ memset(debug_info, 0, sizeof(DEBUG_INFO_T));
+ ee_type = ex_info->header.ex_type;
+ debug_info->type = ee_type;
+ debug_info->more_info = ee_case;
+ md->ex_type = ee_type;
+
+ if(*((char *)ex_info+CCCI_EXREC_OFFSET_OFFENDER) != 0xCC) {
+ memcpy(debug_info->fatal_error.offender, (char *)ex_info+CCCI_EXREC_OFFSET_OFFENDER, sizeof(debug_info->fatal_error.offender)-1);
+ debug_info->fatal_error.offender[sizeof(debug_info->fatal_error.offender)-1] = '\0';
+ } else {
+ debug_info->fatal_error.offender[0] = '\0';
+ }
+
+ switch (ee_type)
+ {
+ case MD_EX_TYPE_INVALID:
+ debug_info->name="INVALID";
+ break;
+
+ case MD_EX_TYPE_UNDEF:
+ debug_info->name="Fatal error (undefine)";
+ debug_info->fatal_error.err_code1=ex_info->content.fatalerr.error_code.code1;
+ debug_info->fatal_error.err_code2=ex_info->content.fatalerr.error_code.code2;
+ break;
+
+ case MD_EX_TYPE_SWI:
+ debug_info->name="Fatal error (swi)";
+ debug_info->fatal_error.err_code1=ex_info->content.fatalerr.error_code.code1;
+ debug_info->fatal_error.err_code2=ex_info->content.fatalerr.error_code.code2;
+ break;
+
+ case MD_EX_TYPE_PREF_ABT:
+ debug_info->name="Fatal error (prefetch abort)";
+ debug_info->fatal_error.err_code1=ex_info->content.fatalerr.error_code.code1;
+ debug_info->fatal_error.err_code2=ex_info->content.fatalerr.error_code.code2;
+ break;
+
+ case MD_EX_TYPE_DATA_ABT:
+ debug_info->name="Fatal error (data abort)";
+ debug_info->fatal_error.err_code1=ex_info->content.fatalerr.error_code.code1;
+ debug_info->fatal_error.err_code2=ex_info->content.fatalerr.error_code.code2;
+ break;
+
+ case MD_EX_TYPE_ASSERT:
+ debug_info->name="ASSERT";
+ snprintf(debug_info->assert.file_name,sizeof(debug_info->assert.file_name),
+ ex_info->content.assert.filename);
+ debug_info->assert.line_num = ex_info->content.assert.linenumber;
+ debug_info->assert.parameters[0] = ex_info->content.assert.parameters[0];
+ debug_info->assert.parameters[1] = ex_info->content.assert.parameters[1];
+ debug_info->assert.parameters[2] = ex_info->content.assert.parameters[2];
+ break;
+
+ case MD_EX_TYPE_FATALERR_TASK:
+ debug_info->name="Fatal error (task)";
+ debug_info->fatal_error.err_code1=ex_info->content.fatalerr.error_code.code1;
+ debug_info->fatal_error.err_code2=ex_info->content.fatalerr.error_code.code2;
+ break;
+ case MD_EX_TYPE_C2K_ERROR:
+ debug_info->name="Fatal error (C2K_EXP)";
+ debug_info->fatal_error.err_code1=ex_info->content.fatalerr.error_code.code1;
+ debug_info->fatal_error.err_code2=ex_info->content.fatalerr.error_code.code2;
+ break;
+ case MD_EX_TYPE_FATALERR_BUF:
+ debug_info->name="Fatal error (buff)";
+ debug_info->fatal_error.err_code1=ex_info->content.fatalerr.error_code.code1;
+ debug_info->fatal_error.err_code2=ex_info->content.fatalerr.error_code.code2;
+ break;
+
+ case MD_EX_TYPE_LOCKUP:
+ debug_info->name="Lockup";
+ break;
+
+ case MD_EX_TYPE_ASSERT_DUMP:
+ debug_info->name="ASSERT DUMP";
+ snprintf(debug_info->assert.file_name,sizeof(debug_info->assert.file_name),
+ ex_info->content.assert.filename);
+ debug_info->assert.line_num=ex_info->content.assert.linenumber;
+ break;
+
+ case DSP_EX_TYPE_ASSERT:
+ debug_info->name="MD DMD ASSERT";
+ snprintf(debug_info->dsp_assert.file_name,sizeof(debug_info->dsp_assert.file_name),
+ ex_info->content.assert.filename);
+ debug_info->dsp_assert.line_num = ex_info->content.assert.linenumber;
+ snprintf(debug_info->dsp_assert.execution_unit,sizeof(debug_info->dsp_assert.execution_unit),
+ ex_info->envinfo.execution_unit);
+ debug_info->dsp_assert.parameters[0] = ex_info->content.assert.parameters[0];
+ debug_info->dsp_assert.parameters[1] = ex_info->content.assert.parameters[1];
+ debug_info->dsp_assert.parameters[2] = ex_info->content.assert.parameters[2];
+ break;
+
+ case DSP_EX_TYPE_EXCEPTION:
+ debug_info->name="MD DMD Exception";
+ snprintf(debug_info->dsp_exception.execution_unit,sizeof(debug_info->dsp_exception.execution_unit),
+ ex_info->envinfo.execution_unit);
+ debug_info->dsp_exception.code1 = ex_info->content.fatalerr.error_code.code1;
+ break;
+
+ case DSP_EX_FATAL_ERROR:
+ debug_info->name="MD DMD FATAL ERROR";
+ snprintf(debug_info->dsp_fatal_err.execution_unit,sizeof(debug_info->dsp_fatal_err.execution_unit),
+ ex_info->envinfo.execution_unit);
+ debug_info->dsp_fatal_err.err_code[0] = ex_info->content.fatalerr.error_code.code1;
+ debug_info->dsp_fatal_err.err_code[1] = ex_info->content.fatalerr.error_code.code2;
+ break;
+
+ default:
+ debug_info->name= "UNKNOWN Exception";
+ break;
+ }
+
+ debug_info->ext_mem = ex_info;
+ debug_info->ext_size = sizeof(EX_LOG_T);
+ debug_info->md_image = (void *)md->mem_layout.md_region_vir;
+ debug_info->md_size = MD_IMG_DUMP_SIZE;
+}
+
+void md_ex_monitor_func(unsigned long data)
+{
+ int ee_on_going = 0;
+ int ee_case;
+ int need_update_state = 0;
+ unsigned long flags;
+ unsigned int ee_info_flag = 0;
+ struct ccci_modem *md = (struct ccci_modem *)data;
+#if defined (CONFIG_MTK_AEE_FEATURE)
+ CCCI_INF_MSG(md->index, KERN, "MD exception timer 1:disable tracing\n");
+ tracing_off();
+#endif
+ CCCI_INF_MSG(md->index, KERN, "MD exception timer 1! ee=%x\n", md->ee_info_flag);
+ spin_lock_irqsave(&md->ctrl_lock, flags);
+ if((1<<MD_EE_DUMP_ON_GOING) & md->ee_info_flag) {
+ ee_on_going = 1;
+ } else {
+ ee_info_flag = md->ee_info_flag;
+ md->ee_info_flag |= (1<<MD_EE_DUMP_ON_GOING);
+ }
+ spin_unlock_irqrestore(&md->ctrl_lock, flags);
+
+ if(ee_on_going)
+ return;
+
+ if ((ee_info_flag&((1<<MD_EE_MSG_GET)|(1<<MD_EE_OK_MSG_GET)|(1<<MD_EE_SWINT_GET))) == \
+ ((1<<MD_EE_MSG_GET)|(1<<MD_EE_OK_MSG_GET)|(1<<MD_EE_SWINT_GET))) {
+ ee_case = MD_EE_CASE_NORMAL;
+ CCCI_DBG_MSG(md->index, KERN, "Recv SWINT & MD_EX & MD_EX_REC_OK\n");
+ if (ee_info_flag & (1 << MD_EE_AP_MASK_I_BIT_TOO_LONG)) {
+ ee_case = MD_EE_CASE_AP_MASK_I_BIT_TOO_LONG;
+ }
+ } else if(!(ee_info_flag&(1<<MD_EE_SWINT_GET)) && (ee_info_flag&((1<<MD_EE_MSG_GET)|(1<<MD_EE_SWINT_GET)))) {
+ ee_case = MD_EE_CASE_SWINT_MISSING;
+ CCCI_INF_MSG(md->index, KERN, \
+ "SWINT missing, ee_info_flag=%x\n", ee_info_flag);
+ } else if((ee_info_flag&((1<<MD_EE_MSG_GET)|(1<<MD_EE_SWINT_GET))) & (1<<MD_EE_MSG_GET)) {
+ ee_case = MD_EE_CASE_ONLY_EX;
+ CCCI_INF_MSG(md->index, KERN, \
+ "Only recv SWINT & MD_EX.\n");
+ if (ee_info_flag & (1 << MD_EE_AP_MASK_I_BIT_TOO_LONG)) {
+ ee_case = MD_EE_CASE_AP_MASK_I_BIT_TOO_LONG;
+ }
+ } else if((ee_info_flag&((1<<MD_EE_OK_MSG_GET)|(1<<MD_EE_SWINT_GET))) & (1<<MD_EE_OK_MSG_GET)) {
+ ee_case = MD_EE_CASE_ONLY_EX_OK;
+ CCCI_INF_MSG(md->index, KERN, \
+ "Only recv SWINT & MD_EX_OK\n");
+ if (ee_info_flag & (1 << MD_EE_AP_MASK_I_BIT_TOO_LONG)) {
+ ee_case = MD_EE_CASE_AP_MASK_I_BIT_TOO_LONG;
+ }
+ } else if(ee_info_flag&(1<<MD_EE_SWINT_GET)) {
+ ee_case = MD_EE_CASE_ONLY_SWINT;
+ CCCI_INF_MSG(md->index, KERN, \
+ "Only recv SWINT.\n");
+ if((ee_info_flag&(1<<MD_STATE_UPDATE))==0){
+ need_update_state = 1;
+ }
+ } else if (ee_info_flag & (1 << MD_EE_AP_MASK_I_BIT_TOO_LONG)) {
+ ee_case = MD_EE_CASE_AP_MASK_I_BIT_TOO_LONG;
+ if((ee_info_flag&(1<<MD_STATE_UPDATE))==0){
+ need_update_state = 1;
+ }
+ } else if(ee_info_flag&(1<<MD_EE_FOUND_BY_ISR)) {
+ ee_case = MD_EE_CASE_ISR_TRG;
+ if((ee_info_flag&(1<<MD_STATE_UPDATE))==0){
+ need_update_state = 1;
+ }
+ } else if(ee_info_flag&(1<<MD_EE_FOUND_BY_TX)) {
+ ee_case = MD_EE_CASE_TX_TRG;
+ if((ee_info_flag&(1<<MD_STATE_UPDATE))==0){
+ need_update_state = 1;
+ }
+ } else if(ee_info_flag&(1<<MD_EE_PENDING_TOO_LONG)) {
+ ee_case = MD_EE_CASE_NO_RESPONSE;
+ if((ee_info_flag&(1<<MD_STATE_UPDATE))==0){
+ need_update_state = 1;
+ }
+ } else if(ee_info_flag&(1<<MD_EE_WDT_GET)) {
+ ee_case = MD_EE_CASE_WDT;
+ if((ee_info_flag&(1<<MD_STATE_UPDATE))==0){
+ need_update_state = 1;
+ }
+ } else {
+ CCCI_ERR_MSG(md->index, KERN, "Invalid MD_EX, ee_info=%x\n", ee_info_flag);
+ goto _dump_done;
+ }
+
+ if(need_update_state) {
+ //md->boot_stage = MD_BOOT_STAGE_EXCEPTION;
+ md->config.setting |= MD_SETTING_RELOAD;
+ md->ops->broadcast_state(md, EXCEPTION);
+ }
+
+ if(md->boot_stage < MD_BOOT_STAGE_2) {
+ md->ops->broadcast_state(md, BOOT_FAIL);
+ }
+
+ //ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_NOTIFY, ee_case); // unsafe in timer context
+ md->debug_info.more_info = ee_case;
+ // Dump MD EE info
+ CCCI_INF_MSG(md->index, KERN, "Dump MD EX log\n");
+ ccci_mem_dump(md->index, md->smem_layout.ccci_exp_smem_base_vir, md->smem_layout.ccci_exp_dump_size);
+ // Dump MD register
+ md->ops->dump_info(md, DUMP_FLAG_REG, NULL, 0);
+ mod_timer(&md->ex_monitor2, jiffies+EX_TIMER_MD_EX_REC_OK*HZ);
+
+_dump_done:
+ return;
+}
+EXPORT_SYMBOL(md_ex_monitor_func);
+
+void md_ex_monitor2_func(unsigned long data)
+{
+ struct ccci_modem *md = (struct ccci_modem *)data;
+ unsigned long flags;
+
+ int ee_on_going = 0;
+
+ CCCI_INF_MSG(md->index, KERN, "MD exception timer 2! ee=%x\n", md->ee_info_flag);
+
+ spin_lock_irqsave(&md->ctrl_lock, flags);
+ if((1<<MD_EE_TIMER2_DUMP_ON_GOING) & md->ee_info_flag) {
+ ee_on_going = 1;
+ } else {
+ md->ee_info_flag |= (1<<MD_EE_TIMER2_DUMP_ON_GOING);
+ }
+ spin_unlock_irqrestore(&md->ctrl_lock, flags);
+
+ if(ee_on_going)
+ return;
+
+ ccci_md_exception(md);
+ ccci_ee_info_dump(md);
+
+ spin_lock_irqsave(&md->ctrl_lock, flags);
+ md->ee_info_flag = 0; // this should be the last action of a regular exception flow, clear flag for reset MD later
+ spin_unlock_irqrestore(&md->ctrl_lock, flags);
+
+ CCCI_INF_MSG(md->index, KERN, "Enable WDT at exception exit.");
+ md->ops->ee_callback(md, EE_FLAG_ENABLE_WDT);
+}
+EXPORT_SYMBOL(md_ex_monitor2_func);
+
+void md_bootup_timeout_func(unsigned long data)
+{
+ struct ccci_modem *md = (struct ccci_modem *)data;
+ char ex_info[EE_BUF_LEN]="";
+
+ CCCI_INF_MSG(md->index, KERN, "MD_BOOT_HS%d_FAIL!\n", (md->boot_stage+1));
+ md->ops->broadcast_state(md, BOOT_FAIL);
+ if(md->config.setting & MD_SETTING_STOP_RETRY_BOOT)
+ return;
+
+ //ccci_send_virtual_md_msg(md, CCCI_MONITOR_CH, CCCI_MD_MSG_BOOT_TIMEOUT, 0);
+ snprintf(ex_info, EE_BUF_LEN, "\n[Others] MD_BOOT_UP_FAIL(HS%d)\n", (md->boot_stage+1));
+ CCCI_INF_MSG(md->index, KERN, "Dump MD image memory\n");
+ ccci_mem_dump(md->index, (void*)md->mem_layout.md_region_vir, MD_IMG_DUMP_SIZE);
+ CCCI_INF_MSG(md->index, KERN, "Dump MD layout struct\n");
+ ccci_mem_dump(md->index, &md->mem_layout, sizeof(struct ccci_mem_layout));
+ md->ops->dump_info(md, DUMP_FLAG_CLDMA, NULL, 0);
+
+ if(md->boot_stage == MD_BOOT_STAGE_0) {
+ // Handshake 1 fail
+ ccci_aed(md, CCCI_AED_DUMP_CCIF_REG|CCCI_AED_DUMP_MD_IMG_MEM, ex_info, DB_OPT_DEFAULT);
+ } else if(md->boot_stage == MD_BOOT_STAGE_1) {
+ // Handshake 2 fail
+ CCCI_INF_MSG(md->index, KERN, "Dump MD EX log\n");
+ ccci_mem_dump(md->index, md->smem_layout.ccci_exp_smem_base_vir, md->smem_layout.ccci_exp_dump_size);
+
+ ccci_aed(md, CCCI_AED_DUMP_CCIF_REG|CCCI_AED_DUMP_EX_MEM, ex_info, DB_OPT_FTRACE);
+ }
+}
+EXPORT_SYMBOL(md_bootup_timeout_func);
+