예제 #1
0
/**
@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;
}
예제 #2
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));
}
예제 #3
0
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;
}
예제 #4
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);
}
예제 #7
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);
}
예제 #8
0
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
}
예제 #11
0
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
}