/** @brief check whether or not IPC link is active @param mld the pointer to a mem_link_device instance @retval "TRUE" if IPC via the mem_link_device instance is possible. @retval "FALSE" otherwise. */ static inline bool ipc_active(struct mem_link_device *mld) { struct link_device *ld = &mld->link_dev; struct modem_ctl *mc = ld->mc; if (unlikely(!cp_online(mc))) { mif_err("%s<->%s: %s.state %s != ONLINE <%pf>\n", ld->name, mc->name, mc->name, mc_state(mc), CALLER); return false; } if (atomic_read(&mc->forced_cp_crash)) { mif_err("%s<->%s: ERR! forced_cp_crash:%d <%pf>\n", ld->name, mc->name, atomic_read(&mc->forced_cp_crash), CALLER); return false; } if (mld->dpram_magic) { unsigned int magic = get_magic(mld); unsigned int access = get_access(mld); if (magic != MEM_IPC_MAGIC || access != 1) { mif_err("%s<->%s: ERR! magic:0x%X access:%d <%pf>\n", ld->name, mc->name, magic, access, CALLER); return false; } } return true; }
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)); }
static int ss300_on(struct modem_ctl *mc) { struct link_device *ld = get_current_link(mc->iod); int cp_on; int cp_reset; int cp_active; int cp_status; unsigned long flags; mif_err("+++\n"); spin_lock_irqsave(&ld->lock, flags); cp_on = gpio_get_value(mc->gpio_cp_on); cp_reset = gpio_get_value(mc->gpio_cp_reset); cp_active = gpio_get_value(mc->gpio_phone_active); cp_status = gpio_get_value(mc->gpio_cp_status); mif_err("state:%s cp_on:%d cp_reset:%d cp_active:%d cp_status:%d\n", mc_state(mc), cp_on, cp_reset, cp_active, cp_status); mc->phone_state = STATE_OFFLINE; gpio_set_value(mc->gpio_pda_active, 1); 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->ready) ld->ready(ld); spin_unlock_irqrestore(&ld->lock, flags); mif_disable_irq(&mc->irq_cp_active); gpio_set_value(mc->gpio_cp_on, 0); msleep(100); gpio_set_value(mc->gpio_cp_reset, 0); msleep(500); gpio_set_value(mc->gpio_cp_on, 1); msleep(100); if (ld->reset) ld->reset(ld); gpio_set_value(mc->gpio_cp_reset, 1); msleep(300); mif_err("---\n"); return 0; }
static void print_mc_state(struct modem_ctl *mc) { int cp_on = gpio_get_value(mc->gpio_cp_on); int cp_reset = gpio_get_value(mc->gpio_cp_reset); int cp_active = gpio_get_value(mc->gpio_phone_active); int cp_status = gpio_get_value(mc->gpio_cp_status); mif_info("%s: %pf: MC state:%s on:%d reset:%d active:%d status:%d\n", mc->name, CALLER, mc_state(mc), cp_on, cp_reset, cp_active, cp_status); }
static void send_int2cp(struct mem_link_device *mld, u16 mask) { struct link_device *ld = &mld->link_dev; struct modem_ctl *mc = ld->mc; if (!cp_online(mc)) mif_err("%s: mask 0x%04X (%s.state == %s)\n", ld->name, mask, mc->name, mc_state(mc)); c2c_send_interrupt(mask); }
static void send_ap2cp_irq(struct mem_link_device *mld, u16 mask) { #if 0/*def DEBUG_MODEM_IF*/ struct link_device *ld = &mld->link_dev; struct modem_ctl *mc = ld->mc; if (!cp_online(mc)) mif_err("%s: mask 0x%04X (%s.state == %s)\n", ld->name, mask, mc->name, mc_state(mc)); #endif mbox_set_value(mld->mbx_ap2cp_msg, mask); mbox_set_interrupt(mld->int_ap2cp_msg); }
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 int ss300_off(struct modem_ctl *mc) { struct link_device *ld = get_current_link(mc->iod); int cp_on; int cp_reset; int cp_active; int cp_status; unsigned long flags; mif_err("+++\n"); spin_lock_irqsave(&ld->lock, flags); cp_on = gpio_get_value(mc->gpio_cp_on); cp_reset = gpio_get_value(mc->gpio_cp_reset); cp_active = gpio_get_value(mc->gpio_phone_active); cp_status = gpio_get_value(mc->gpio_cp_status); mif_err("state:%s cp_on:%d cp_reset:%d cp_active:%d cp_status:%d\n", mc_state(mc), cp_on, cp_reset, cp_active, cp_status); if (mc->phone_state == STATE_OFFLINE) goto exit; mc->phone_state = STATE_OFFLINE; if (ld->off) ld->off(ld); if (gpio_get_value(mc->gpio_cp_on)) { if (gpio_get_value(mc->gpio_cp_reset)) { mif_err("%s: cp_reset -> 0\n", mc->name); gpio_set_value(mc->gpio_cp_reset, 0); } } else { mif_err("%s: cp_on == 0\n", mc->name); } exit: spin_unlock_irqrestore(&ld->lock, flags); mif_err("---\n"); return 0; }
/** @brief common interrupt handler for all MEMORY interfaces @param mld the pointer to a mem_link_device instance @param msb the pointer to a mst_buff instance */ void mem_irq_handler(struct mem_link_device *mld, struct mst_buff *msb) { struct link_device *ld = &mld->link_dev; struct modem_ctl *mc = ld->mc; u16 intr = msb->snapshot.int2ap; if (unlikely(!int_valid(intr))) { mif_err("%s: ERR! invalid intr 0x%X\n", ld->name, intr); msb_free(msb); return; } if (unlikely(!rx_possible(mc))) { mif_err("%s: ERR! %s.state == %s\n", ld->name, mc->name, mc_state(mc)); msb_free(msb); return; } msb_queue_tail(&mld->msb_rxq, msb); tasklet_hi_schedule(&mld->rx_tsk); }
/** @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 }