static int ss333_force_crash_exit(struct modem_ctl *mc) { struct io_device *iod = mc->iod; struct link_device *ld = get_current_link(iod); mif_err("+++\n"); mif_add_timer(&mc->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, handle_no_response_cp_crash, (unsigned long)mc); if (mc->wake_lock && !wake_lock_active(mc->wake_lock)) { wake_lock(mc->wake_lock); mif_err("%s->wake_lock locked\n", mc->name); } if (ld->off) ld->off(ld); gpio_set_value(mc->gpio_ap_dump_int, 1); mif_info("set ap_dump_int(%d) to high=%d\n", mc->gpio_ap_dump_int, gpio_get_value(mc->gpio_ap_dump_int)); mif_err("---\n"); return 0; }
static int _cmc221_idpram_upload(struct dpram_link_device *dpld, struct dpram_dump_arg *dumparg) { struct link_device *ld = &dpld->ld; int ret; u8 __iomem *src; int buff_size = CMC22x_DUMP_BUFF_SIZE; if ((dpld->dump_rcvd & 0x1) == 0) cmc221_idpram_send_msg(dpld, CMC22x_1ST_BUFF_READY); else cmc221_idpram_send_msg(dpld, CMC22x_2ND_BUFF_READY); init_completion(&dpld->dump_recv_done); mif_add_timer(&dpld->dump_timer, DUMP_WAIT_TIMEOUT, _cmc221_idpram_wait_dump, (unsigned long)dpld); ret = wait_for_completion_interruptible_timeout( &dpld->dump_recv_done, DUMP_TIMEOUT); if (!ret) { mif_info("%s: ERR! CP didn't send dump data!!!\n", ld->name); goto err_out; } if (cmc221_idpram_recv_msg(dpld) == CMC22x_CP_DUMP_END) { mif_info("%s: CMC22x_CP_DUMP_END\n", ld->name); return 0; } if ((dpld->dump_rcvd & 0x1) == 0) src = dpld->ul_map.buff; else src = dpld->ul_map.buff + CMC22x_DUMP_BUFF_SIZE; memcpy(dpld->buff, src, buff_size); ret = copy_to_user(dumparg->buff, dpld->buff, buff_size); if (ret < 0) { mif_info("%s: ERR! copy_to_user fail\n", ld->name); goto err_out; } dpld->dump_rcvd++; return buff_size; err_out: return -EIO; }
static int cmc221_idpram_upload(struct dpram_link_device *dpld, struct dpram_dump_arg *dumparg) { int ret; u8 __iomem *src; int buff_size = CMC22x_DUMP_BUFF_SIZE; if ((dpld->crash_rcvd & 0x1) == 0) cmc221_idpram_send_msg(dpld, CMC22x_1ST_BUFF_READY); else cmc221_idpram_send_msg(dpld, CMC22x_2ND_BUFF_READY); init_completion(&dpld->crash_cmpl); mif_add_timer(&dpld->crash_timer, DUMP_WAIT_TIMEOUT, cmc221_idpram_wait_dump, (unsigned long)dpld); ret = wait_for_completion_timeout(&dpld->crash_cmpl, DUMP_TIMEOUT); if (!ret) { mif_info("ERR! no dump from CP!!!\n"); goto err_out; } if (cmc221_idpram_recv_msg(dpld) == CMC22x_CP_DUMP_END) { mif_info("recv CMC22x_CP_DUMP_END\n"); return 0; } if ((dpld->crash_rcvd & 0x1) == 0) src = dpld->ul_map.buff; else src = dpld->ul_map.buff + CMC22x_DUMP_BUFF_SIZE; memcpy(dpld->buff, src, buff_size); ret = copy_to_user(dumparg->buff, dpld->buff, buff_size); if (ret < 0) { mif_info("ERR! copy_to_user fail\n"); goto err_out; } dpld->crash_rcvd++; return buff_size; err_out: return -EIO; }
static int ss300_force_crash_exit(struct modem_ctl *mc) { mif_err("+++\n"); mif_add_timer(&mc->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, handle_no_response_cp_crash, (unsigned long)mc); if (mc->wake_lock && !wake_lock_active(mc->wake_lock)) { wake_lock(mc->wake_lock); mif_err("%s->wake_lock locked\n", mc->name); } gpio_set_value(mc->gpio_ap_dump_int, 1); mif_info("set ap_dump_int(%d) to high=%d\n", mc->gpio_ap_dump_int, gpio_get_value(mc->gpio_ap_dump_int)); mif_err("---\n"); return 0; }
static inline void start_pm_wdog(struct modem_link_pm *pm, enum pm_state state, enum pm_state w_state, enum pm_event w_event, unsigned long ms) { struct pm_wdog *wdog = &pm->wdog; struct timer_list *timer = &wdog->timer; unsigned long expire = msecs_to_jiffies(ms); wdog->state = state; wdog->w_state = w_state; wdog->w_event = w_event; #if 0 snprintf(wdog->msg, MAX_STR_LEN, "%s: PM WDOG wait for {%s@%s}", pm->link_name, pm_event2str(w_event), pm_state2str(state)); #endif mif_add_timer(timer, expire, pm_wdog_bark, (unsigned long)wdog); }
static int trigger_force_cp_crash(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; if (ld->mode == LINK_MODE_ULOAD) { mif_err("%s: CP crash is already in progress\n", ld->mc->name); return 0; } ld->mode = LINK_MODE_ULOAD; mif_err("%s: called by %pf\n", ld->name, __builtin_return_address(0)); dpram_wake_up(dpld); send_intr(dpld, INT_CMD(INT_CMD_CRASH_EXIT)); mif_add_timer(&dpld->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, handle_no_crash_ack, (unsigned long)dpld); return 0; }
static void _cmc221_idpram_wait_dump(unsigned long arg) { struct dpram_link_device *dpld = (struct dpram_link_device *)arg; u16 msg; msg = cmc221_idpram_recv_msg(dpld); if (msg == CMC22x_CP_DUMP_END) { complete_all(&dpld->dump_recv_done); return; } if (((dpld->dump_rcvd & 0x1) == 0) && (msg == CMC22x_1ST_BUFF_FULL)) { complete_all(&dpld->dump_recv_done); return; } if (((dpld->dump_rcvd & 0x1) == 1) && (msg == CMC22x_2ND_BUFF_FULL)) { complete_all(&dpld->dump_recv_done); return; } mif_add_timer(&dpld->dump_timer, DUMP_WAIT_TIMEOUT, _cmc221_idpram_wait_dump, (unsigned long)dpld); }
/** @brief trigger an enforced CP crash @param mld the pointer to a mem_link_device instance */ void mem_forced_cp_crash(struct mem_link_device *mld) { struct link_device *ld = &mld->link_dev; struct modem_ctl *mc = ld->mc; unsigned long flags; bool duplicated = false; #ifdef DEBUG_MODEM_IF struct utc_time t; #endif #ifdef DEBUG_MODEM_IF get_utc_time(&t); #endif /* Disable normal IPC */ set_magic(mld, MEM_CRASH_MAGIC); set_access(mld, 0); spin_lock_irqsave(&mld->lock, flags); if (mld->forced_cp_crash) duplicated = true; else mld->forced_cp_crash = true; spin_unlock_irqrestore(&mld->lock, flags); if (duplicated) { #ifdef DEBUG_MODEM_IF evt_log(HMSU_FMT " %s: %s: ALREADY in progress <%pf>\n", t.hour, t.min, t.sec, t.us, CALLEE, ld->name, CALLER); #endif return; } if (!cp_online(mc)) { #ifdef DEBUG_MODEM_IF evt_log(HMSU_FMT " %s: %s: %s.state %s != ONLINE <%pf>\n", t.hour, t.min, t.sec, t.us, CALLEE, ld->name, mc->name, mc_state(mc), CALLER); #endif return; } if (!wake_lock_active(&mld->dump_wlock)) wake_lock(&mld->dump_wlock); stop_net_ifaces(ld); /** * If there is no CRASH_ACK from a CP in FORCE_CRASH_ACK_TIMEOUT, * handle_no_cp_crash_ack() will be executed. */ mif_add_timer(&mld->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, handle_no_cp_crash_ack, (unsigned long)mld); /* Send CRASH_EXIT command to a CP */ send_ipc_irq(mld, cmd2int(CMD_CRASH_EXIT)); #ifdef DEBUG_MODEM_IF evt_log(HMSU_FMT " CRASH_EXIT: %s->%s: CP_CRASH_REQ <by %pf>\n", t.hour, t.min, t.sec, t.us, ld->name, mc->name, CALLER); if (in_interrupt()) queue_work(system_nrt_wq, &mld->dump_work); else save_mem_dump(mld); #endif }
void mem_forced_cp_crash(struct mem_link_device *mld) { struct link_device *ld = &mld->link_dev; struct modem_ctl *mc = ld->mc; bool duplicated = false; unsigned long flags; /* Disable normal IPC */ set_magic(mld, MEM_CRASH_MAGIC); set_access(mld, 0); spin_lock_irqsave(&mld->lock, flags); if (atomic_read(&mc->forced_cp_crash)) duplicated = true; else atomic_set(&mc->forced_cp_crash, 1); spin_unlock_irqrestore(&mld->lock, flags); if (duplicated) { evt_log(0, "%s: %s: ALREADY in progress <%pf>\n", FUNC, ld->name, CALLER); return; } if (!cp_online(mc)) { evt_log(0, "%s: %s: %s.state %s != ONLINE <%pf>\n", FUNC, ld->name, mc->name, mc_state(mc), CALLER); return; } if (mc->wake_lock) { if (!wake_lock_active(mc->wake_lock)) { wake_lock(mc->wake_lock); mif_err("%s->wake_lock locked\n", mc->name); } } if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_DUMP)) { stop_net_ifaces(ld); if (mld->debug_info) mld->debug_info(); /** * If there is no CRASH_ACK from CP in a timeout, * handle_no_cp_crash_ack() will be executed. */ mif_add_timer(&mc->crash_ack_timer, FORCE_CRASH_ACK_TIMEOUT, handle_no_cp_crash_ack, (unsigned long)mld); /* Send CRASH_EXIT command to a CP */ send_ipc_irq(mld, cmd2int(CMD_CRASH_EXIT)); } else { modemctl_notify_event(MDM_EVENT_CP_FORCE_CRASH); } evt_log(0, "%s->%s: CP_CRASH_REQ <%pf>\n", ld->name, mc->name, CALLER); #ifdef DEBUG_MODEM_IF if (in_interrupt()) queue_work(system_nrt_wq, &mld->dump_work); else save_mem_dump(mld); #endif }