/** @brief function for the @b dump_start method in a link_device instance @param ld the pointer to a link_device instance @param iod the pointer to an io_device instance */ int mem_start_upload(struct link_device *ld, struct io_device *iod) { struct mem_link_device *mld = to_mem_link_device(ld); if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_DUMP)) sbd_deactivate(&mld->sbd_link_dev); reset_ipc_map(mld); if (mld->attrs & LINK_ATTR(LINK_ATTR_DUMP_ALIGNED)) ld->aligned = true; else ld->aligned = false; if (mld->dpram_magic) { unsigned int magic; set_magic(mld, MEM_DUMP_MAGIC); magic = get_magic(mld); if (magic != MEM_DUMP_MAGIC) { mif_err("%s: ERR! magic 0x%08X != DUMP_MAGIC 0x%08X\n", ld->name, magic, MEM_DUMP_MAGIC); return -EFAULT; } mif_info("%s: magic == 0x%08X\n", ld->name, magic); } return 0; }
static int mem_start_download(struct link_device *ld, struct io_device *iod) { struct mem_link_device *mld = to_mem_link_device(ld); reset_ipc_map(mld); #ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_BOOT)) sbd_deactivate(&mld->sbd_link_dev); #endif if (mld->attrs & LINK_ATTR(LINK_ATTR_BOOT_ALIGNED)) ld->aligned = true; else ld->aligned = false; if (mld->dpram_magic) { unsigned int magic; set_magic(mld, MEM_BOOT_MAGIC); magic = get_magic(mld); if (magic != MEM_BOOT_MAGIC) { mif_err("%s: ERR! magic 0x%08X != BOOT_MAGIC 0x%08X\n", ld->name, magic, MEM_BOOT_MAGIC); return -EFAULT; } mif_err("%s: magic == 0x%08X\n", ld->name, magic); } return 0; }
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)); }
struct mem_link_device *mem_create_link_device(enum mem_iface_type type, struct modem_data *modem) { struct mem_link_device *mld; struct link_device *ld; int i; mif_err("+++\n"); if (modem->ipc_version < SIPC_VER_50) { mif_err("%s<->%s: ERR! IPC version %d < SIPC_VER_50\n", modem->link_name, modem->name, modem->ipc_version); return NULL; } /* ** Alloc an instance of mem_link_device structure */ mld = kzalloc(sizeof(struct mem_link_device), GFP_KERNEL); if (!mld) { mif_err("%s<->%s: ERR! mld kzalloc fail\n", modem->link_name, modem->name); return NULL; } /* ** Retrieve modem-specific attributes value */ mld->type = type; mld->attrs = modem->link_attrs; /*====================================================================*\ Initialize "memory snapshot buffer (MSB)" framework \*====================================================================*/ if (msb_init() < 0) { mif_err("%s<->%s: ERR! msb_init() fail\n", modem->link_name, modem->name); goto error; } /*====================================================================*\ Set attributes as a "link_device" \*====================================================================*/ ld = &mld->link_dev; ld->name = modem->link_name; if (mld->attrs & LINK_ATTR(LINK_ATTR_SBD_IPC)) { mif_err("%s<->%s: LINK_ATTR_SBD_IPC\n", ld->name, modem->name); ld->sbd_ipc = true; } if (mld->attrs & LINK_ATTR(LINK_ATTR_IPC_ALIGNED)) { mif_err("%s<->%s: LINK_ATTR_IPC_ALIGNED\n", ld->name, modem->name); ld->aligned = true; } ld->ipc_version = modem->ipc_version; ld->mdm_data = modem; /* Set up link device methods */ ld->init_comm = mem_init_comm; #ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH ld->terminate_comm = mem_terminate_comm; #endif ld->send = mem_send; ld->boot_on = mem_boot_on; if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_BOOT)) { if (mld->attrs & LINK_ATTR(LINK_ATTR_XMIT_BTDLR)) ld->xmit_boot = mem_xmit_boot; ld->dload_start = mem_start_download; ld->firm_update = mem_update_firm_info; ld->security_req = mem_security_request; } ld->force_dump = mem_force_dump; if (mld->attrs & LINK_ATTR(LINK_ATTR_MEM_DUMP)) { ld->dump_start = mem_start_upload; } ld->close_tx = mem_close_tx; INIT_LIST_HEAD(&ld->list); skb_queue_head_init(&ld->sk_fmt_tx_q); skb_queue_head_init(&ld->sk_raw_tx_q); skb_queue_head_init(&ld->sk_fmt_rx_q); skb_queue_head_init(&ld->sk_raw_rx_q); for (i = 0; i < MAX_SIPC5_DEVICES; i++) { spin_lock_init(&ld->tx_lock[i]); spin_lock_init(&ld->rx_lock[i]); } spin_lock_init(&ld->netif_lock); atomic_set(&ld->netif_stopped, 0); if (mem_rx_setup(ld) < 0) goto error; /*====================================================================*\ Set attributes as a "memory link_device" \*====================================================================*/ if (mld->attrs & LINK_ATTR(LINK_ATTR_DPRAM_MAGIC)) { mif_err("%s<->%s: LINK_ATTR_DPRAM_MAGIC\n", ld->name, modem->name); mld->dpram_magic = true; } #ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH if (mld->attrs & LINK_ATTR(LINK_ATTR_IOSM_MESSAGE)) { mif_err("%s<->%s: MODEM_ATTR_IOSM_MESSAGE\n", ld->name, modem->name); mld->iosm = true; mld->cmd_handler = iosm_event_bh; } else { mld->cmd_handler = mem_cmd_handler; } #else mld->cmd_handler = mem_cmd_handler; #endif /*====================================================================*\ Initialize MEM locks, completions, bottom halves, etc \*====================================================================*/ spin_lock_init(&mld->lock); /* ** Initialize variables for TX & RX */ msb_queue_head_init(&mld->msb_rxq); msb_queue_head_init(&mld->msb_log); tasklet_init(&mld->rx_tsk, mem_rx_task, (unsigned long)mld); hrtimer_init(&mld->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); mld->tx_timer.function = tx_timer_func; #ifdef CONFIG_LINK_DEVICE_WITH_SBD_ARCH hrtimer_init(&mld->sbd_tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); mld->sbd_tx_timer.function = sbd_tx_timer_func; INIT_WORK(&mld->iosm_w, iosm_event_work); #endif /* ** Initialize variables for CP booting and crash dump */ INIT_DELAYED_WORK(&mld->udl_rx_dwork, udl_rx_work); #ifdef DEBUG_MODEM_IF INIT_WORK(&mld->dump_work, mem_dump_work); #endif mif_err("---\n"); return mld; error: kfree(mld); mif_err("xxx\n"); return NULL; }
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 }