/** @brief function for the @b init_comm method in a link_device instance @param ld the pointer to a link_device instance @param iod the pointer to an io_device instance */ static int mem_init_comm(struct link_device *ld, struct io_device *iod) { struct mem_link_device *mld = to_mem_link_device(ld); struct modem_ctl *mc = ld->mc; struct io_device *check_iod; int id = iod->id; int fmt2rfs = (SIPC5_CH_ID_RFS_0 - SIPC5_CH_ID_FMT_0); int rfs2fmt = (SIPC5_CH_ID_FMT_0 - SIPC5_CH_ID_RFS_0); if (atomic_read(&mld->cp_boot_done)) return 0; #ifdef CONFIG_LINK_CONTROL_MSG_IOSM if (mld->iosm) { struct sbd_link_device *sl = &mld->sbd_link_dev; struct sbd_ipc_device *sid = sbd_ch2dev(sl, iod->id); if (atomic_read(&sid->config_done)) { tx_iosm_message(mld, IOSM_A2C_OPEN_CH, (u32 *)&id); return 0; } else { mif_err("%s isn't configured channel\n", iod->name); return -ENODEV; } } #endif switch (id) { case SIPC5_CH_ID_FMT_0 ... SIPC5_CH_ID_FMT_9: check_iod = link_get_iod_with_channel(ld, (id + fmt2rfs)); if (check_iod ? atomic_read(&check_iod->opened) : true) { mif_err("%s: %s->INIT_END->%s\n", ld->name, iod->name, mc->name); send_ipc_irq(mld, cmd2int(CMD_INIT_END)); atomic_set(&mld->cp_boot_done, 1); } else { mif_err("%s is not opened yet\n", check_iod->name); } break; case SIPC5_CH_ID_RFS_0 ... SIPC5_CH_ID_RFS_9: check_iod = link_get_iod_with_channel(ld, (id + rfs2fmt)); if (check_iod) { if (atomic_read(&check_iod->opened)) { mif_err("%s: %s->INIT_END->%s\n", ld->name, iod->name, mc->name); send_ipc_irq(mld, cmd2int(CMD_INIT_END)); atomic_set(&mld->cp_boot_done, 1); } else { mif_err("%s not opened yet\n", check_iod->name); } } break; default: break; } return 0; }
static void cmd_phone_start_handler(struct mem_link_device *mld) { struct link_device *ld = &mld->link_dev; struct modem_ctl *mc = ld->mc; unsigned long flags; int err; mif_info("%s: CP_START <- %s (%s.state:%s cp_boot_done:%d)\n", ld->name, mc->name, mc->name, mc_state(mc), atomic_read(&mld->cp_boot_done)); #ifdef CONFIG_LINK_POWER_MANAGEMENT if (mld->start_pm) mld->start_pm(mld); #endif spin_lock_irqsave(&ld->lock, flags); if (ld->state == LINK_STATE_IPC) { /* If there is no INIT_END command from AP, CP sends a CP_START command to AP periodically until it receives INIT_END from AP even though it has already been in ONLINE state. */ if (rild_ready(ld)) { mif_info("%s: INIT_END -> %s\n", ld->name, mc->name); send_ipc_irq(mld, cmd2int(CMD_INIT_END)); } goto exit; } err = mem_reset_ipc_link(mld); if (err) { mif_err("%s: mem_reset_ipc_link fail(%d)\n", ld->name, err); goto exit; } if (rild_ready(ld)) { mif_info("%s: INIT_END -> %s\n", ld->name, mc->name); send_ipc_irq(mld, cmd2int(CMD_INIT_END)); atomic_set(&mld->cp_boot_done, 1); } ld->state = LINK_STATE_IPC; complete_all(&mc->init_cmpl); exit: spin_unlock_irqrestore(&ld->lock, flags); }
static void cmd_init_start_handler(struct mem_link_device *mld) { struct link_device *ld = &mld->link_dev; struct modem_ctl *mc = ld->mc; int err; mif_info("%s: INIT_START <- %s (%s.state:%s cp_boot_done:%d)\n", ld->name, mc->name, mc->name, mc_state(mc), atomic_read(&mld->cp_boot_done)); if (!ld->sbd_ipc) { mif_err("%s: LINK_ATTR_SBD_IPC is NOT set\n", ld->name); return; } err = init_sbd_link(&mld->sbd_link_dev); if (err < 0) { mif_err("%s: init_sbd_link fail(%d)\n", ld->name, err); return; } if (mld->attrs & LINK_ATTR(LINK_ATTR_IPC_ALIGNED)) ld->aligned = true; else ld->aligned = false; sbd_activate(&mld->sbd_link_dev); mif_info("%s: PIF_INIT_DONE -> %s\n", ld->name, mc->name); send_ipc_irq(mld, cmd2int(CMD_PIF_INIT_DONE)); }
/** @brief function for the @b init_comm method in a link_device instance @param ld the pointer to a link_device instance @param iod the pointer to an io_device instance */ static int mem_init_comm(struct link_device *ld, struct io_device *iod) { struct mem_link_device *mld = to_mem_link_device(ld); struct modem_ctl *mc = ld->mc; struct io_device *check_iod; int id = iod->id; int fmt2rfs = (SIPC5_CH_ID_RFS_0 - SIPC5_CH_ID_FMT_0); int rfs2fmt = (SIPC5_CH_ID_FMT_0 - SIPC5_CH_ID_RFS_0); if (atomic_read(&mld->cp_boot_done)) return 0; switch (id) { case SIPC5_CH_ID_FMT_0 ... SIPC5_CH_ID_FMT_9: check_iod = link_get_iod_with_channel(ld, (id + fmt2rfs)); if (check_iod ? atomic_read(&check_iod->opened) : true) { mif_err("%s: %s->%s: Send 0xC2 (INIT_END)\n", ld->name, iod->name, mc->name); send_ipc_irq(mld, cmd2int(CMD_INIT_END)); atomic_set(&mld->cp_boot_done, 1); } else { mif_err("%s is not opened yet\n", check_iod->name); } break; case SIPC5_CH_ID_RFS_0 ... SIPC5_CH_ID_RFS_9: check_iod = link_get_iod_with_channel(ld, (id + rfs2fmt)); if (check_iod) { if (atomic_read(&check_iod->opened)) { mif_err("%s: %s->%s: Send 0xC2 (INIT_END)\n", ld->name, iod->name, mc->name); send_ipc_irq(mld, cmd2int(CMD_INIT_END)); atomic_set(&mld->cp_boot_done, 1); } else { mif_err("%s not opened yet\n", check_iod->name); } } break; default: break; } return 0; }
/** * iosm wrapper functions called from mem_init_comm function */ void __tx_iosm_message(struct mem_link_device *mld, u8 id) { send_ipc_irq(mld, cmd2int(id)); }
/** @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 }