Ejemplo n.º 1
0
static void cmd_phone_start_handler(struct dpram_link_device *dpld)
{
	struct link_device *ld = &dpld->ld;
	struct io_device *iod = NULL;

	mif_info("%s: Recv 0xC8 (CP_START)\n", ld->name);

	dpram_init_ipc(dpld);

	iod = link_get_iod_with_format(ld, IPC_FMT);
	if (!iod) {
		mif_info("%s: ERR! no iod\n", ld->name);
		return;
	}

	if (dpld->ext_op && dpld->ext_op->cp_start_handler)
		dpld->ext_op->cp_start_handler(dpld);

	if (ld->mc->phone_state != STATE_ONLINE) {
		mif_info("%s: phone_state: %d -> ONLINE\n",
			ld->name, ld->mc->phone_state);
		iod->modem_state_changed(iod, STATE_ONLINE);
	}

	mif_info("%s: Send 0xC2 (INIT_END)\n", ld->name);
	send_intr(dpld, INT_CMD(INT_CMD_INIT_END));
}
Ejemplo n.º 2
0
static int dpram_init_ipc(struct dpram_link_device *dpld)
{
	struct link_device *ld = &dpld->ld;
	int i;

	if (ld->mode == LINK_MODE_IPC &&
	    get_magic(dpld) == DPRAM_MAGIC_CODE &&
	    get_access(dpld) == 1)
		mif_info("%s: IPC already initialized\n", ld->name);

	/* Clear pointers in every circular queue */
	for (i = 0; i < dpld->max_ipc_dev; i++) {
		set_tx_head(dpld, i, 0);
		set_tx_tail(dpld, i, 0);
		set_rx_head(dpld, i, 0);
		set_rx_tail(dpld, i, 0);
	}

	/* Initialize variables for efficient TX/RX processing */
	for (i = 0; i < dpld->max_ipc_dev; i++)
		dpld->iod[i] = link_get_iod_with_format(ld, i);
	dpld->iod[IPC_RAW] = link_get_iod_with_format(ld, IPC_MULTI_RAW);

	if (dpld->iod[IPC_RAW]->recv_skb)
		dpld->use_skb = true;

	for (i = 0; i < dpld->max_ipc_dev; i++) {
		spin_lock_init(&dpld->tx_lock[i]);
		atomic_set(&dpld->res_required[i], 0);
		skb_queue_purge(&dpld->skb_rxq[i]);
	}

	/* Enable IPC */
	atomic_set(&dpld->accessing, 0);

	set_magic(dpld, DPRAM_MAGIC_CODE);
	set_access(dpld, 1);
	if (get_magic(dpld) != DPRAM_MAGIC_CODE || get_access(dpld) != 1)
		return -EACCES;

	ld->mode = LINK_MODE_IPC;

	if (wake_lock_active(&dpld->wlock))
		wake_unlock(&dpld->wlock);

	return 0;
}
Ejemplo n.º 3
0
static void
usb_change_modem_state(struct usb_link_device *usb_ld, enum modem_state state)
{
	struct io_device *iod;

	iod = link_get_iod_with_format(&usb_ld->ld, IPC_FMT);
	if (iod)
		iod->modem_state_changed(iod, state);
}
static void set_modem_state(struct mem_link_device *mld, enum modem_state state)
{
	struct link_device *ld = &mld->link_dev;
	struct io_device *iod;

	/* Change the modem state to STATE_CRASH_EXIT for the FMT IO device */
	iod = link_get_iod_with_format(ld, IPC_FMT);
	if (iod)
		iod->modem_state_changed(iod, state);

	/* time margin for taking state changes by rild */
	mdelay(100);

	/* Change the modem state to STATE_CRASH_EXIT for the BOOT IO device */
	iod = link_get_iod_with_format(ld, IPC_BOOT);
	if (iod)
		iod->modem_state_changed(iod, state);
}
Ejemplo n.º 5
0
static void cmd_crash_reset_handler(struct dpram_link_device *dpld)
{
	struct link_device *ld = &dpld->ld;
	struct io_device *iod = NULL;

	ld->mode = LINK_MODE_ULOAD;

	if (!wake_lock_active(&dpld->wlock))
		wake_lock(&dpld->wlock);

	mif_info("%s: Recv 0xC7 (CRASH_RESET)\n", ld->name);

	iod = link_get_iod_with_format(ld, IPC_FMT);
	iod->modem_state_changed(iod, STATE_CRASH_RESET);

	iod = link_get_iod_with_format(ld, IPC_BOOT);
	iod->modem_state_changed(iod, STATE_CRASH_RESET);
}
static void s5p_idpram_try_resume(struct work_struct *work)
{
	struct idpram_pm_data *pm_data;
	struct dpram_link_device *dpld;
	struct link_device *ld;
	unsigned long delay;
	u16 cmd;
	mif_info("+++\n");

	pm_data = container_of(work, struct idpram_pm_data, resume_dwork.work);
	dpld = container_of(pm_data, struct dpram_link_device, pm_data);
	ld = &dpld->ld;

	if (pm_data->last_msg == INT_CMD(INT_CMD_IDPRAM_RESUME_REQ)) {
		pm_data->last_msg = 0;

		s5p_idpram_set_pm_lock(dpld, 0);
		wake_unlock(&pm_data->hold_wlock);

		delay = msecs_to_jiffies(10);
		schedule_delayed_work(&pm_data->tx_dwork, delay);

		mif_info("%s resumed\n", ld->name);
		goto exit;
	}

	if (pm_data->resume_try_cnt++ < MAX_RESUME_TRY_CNT) {
		mif_info("%s not resumed yet\n", ld->name);

		cmd = INT_CMD(INT_CMD_IDPRAM_RESUME_REQ);
		mif_info("send IDPRAM_RESUME_REQ (0x%X)\n", cmd);
		dpld->send_intr(dpld, cmd);

		delay = msecs_to_jiffies(200);
		schedule_delayed_work(&pm_data->resume_dwork, delay);
	} else {
		struct io_device *iod;
		mif_err("ERR! %s resume T-I-M-E-O-U-T\n", ld->name);

		iod = link_get_iod_with_format(ld, IPC_FMT);
		if (iod)
			iod->modem_state_changed(iod, STATE_CRASH_EXIT);

		wake_unlock(&pm_data->hold_wlock);

		/* hold wakelock until uevnet sent to rild */
		wake_lock_timeout(&pm_data->hold_wlock, HZ*7);
		s5p_idpram_set_pm_lock(dpld, 0);
	}

exit:
	mif_info("---\n");
}
static void qsc6085_error_display_handler(struct dpram_link_device *dpld)
{
	struct link_device *ld = &dpld->ld;
	struct io_device *iod;

	mif_err("recv 0xC9 (CRASH_EXIT)\n");
	mif_err("CP Crash: %s\n", dpld->get_rxq_buff(dpld, IPC_FMT));

	iod = link_get_iod_with_format(ld, IPC_FMT);
	if (iod)
		iod->modem_state_changed(iod, STATE_CRASH_EXIT);
}
Ejemplo n.º 8
0
static void dpram_trigger_crash(struct dpram_link_device *dpld)
{
	struct link_device *ld = &dpld->ld;
	struct io_device *iod;
	int i;

	for (i = 0; i < dpld->max_ipc_dev; i++) {
		mif_info("%s: purging %s_skb_txq\b", ld->name, get_dev_name(i));
		skb_queue_purge(ld->skb_txq[i]);
	}

	iod = link_get_iod_with_format(ld, IPC_FMT);
	iod->modem_state_changed(iod, STATE_CRASH_EXIT);

	iod = link_get_iod_with_format(ld, IPC_BOOT);
	iod->modem_state_changed(iod, STATE_CRASH_EXIT);

	iod = link_get_iod_with_channel(ld, PS_DATA_CH_0);
	if (iod)
		iodevs_for_each(iod->msd, iodev_netif_stop, 0);
}
Ejemplo n.º 9
0
static void dpram_ipc_rx_task(unsigned long data)
{
	struct dpram_link_device *dpld = (struct dpram_link_device *)data;
	struct link_device *ld = &dpld->ld;
	struct io_device *iod;
	struct dpram_rxb *rxb;
	unsigned qlen;
	int i;

	for (i = 0; i < dpld->max_ipc_dev; i++) {
		if (i == IPC_RAW)
			iod = link_get_iod_with_format(ld, IPC_MULTI_RAW);
		else
			iod = link_get_iod_with_format(ld, i);

		qlen = rxbq_size(&dpld->rxbq[i]);
		while (qlen > 0) {
			rxb = rxbq_get_data_rxb(&dpld->rxbq[i]);
			iod->recv(iod, ld, rxb->data, rxb->len);
			rxb_clear(rxb);
			qlen--;
		}
	}
}
static int qsc6085_dump_update(struct dpram_link_device *dpld,
			unsigned long arg)
{
	int ret;
	struct link_device *ld = &dpld->ld;
	struct io_device *iod = link_get_iod_with_format(ld, IPC_RAMDUMP);
	struct memif_uload_map *ul_map = &dpld->ul_map;
	struct cp_ramdump_status *dump_stat = &ld->msd->dump_stat;
	char *buff = dpld->buff;
	struct qsc6085_dump_command dump_cmd;

	while (iod->sk_rx_q.qlen > 0)
		usleep_range(1000, 1100);

	memset(&dump_cmd, 0, sizeof(dump_cmd));
	dump_cmd.addr = dump_stat->addr;
	dump_cmd.size = min(dump_stat->rest, ul_map->space);
	dump_cmd.copyto_offset = 0x38000010;

	memcpy_toio(ul_map->cmd, &dump_cmd, ul_map->cmd_size);

	dpld->send_intr(dpld, CMD_CP_RAMDUMP_SEND_REQ);
	ret = wait_for_completion_interruptible_timeout(&dpld->crash_cmpl,
			RAMDUMP_CMD_TIMEOUT);
	if (!ret) {
		dump_stat->dump_size = 0;
		mif_err("ERR! no response to CP_RAMDUMP_SEND_REQ\n");
		ret = -EIO;
		goto exit;
	}

	memcpy_fromio(buff, ul_map->buff, dump_cmd.size);

	ret = iod->recv(iod, ld, buff, dump_cmd.size);
	if (ret < 0)
		goto exit;

	dump_stat->addr += dump_cmd.size;
	dump_stat->rcvd += dump_cmd.size;
	dump_stat->rest -= dump_cmd.size;
	mif_info("rest = %u bytes\n", dump_stat->rest);

	ret = dump_cmd.size;

exit:
	return ret;
}
static void qsc6085_start_handler(struct dpram_link_device *dpld)
{
	struct link_device *ld = &dpld->ld;
	struct io_device *iod;

	mif_info("recv 0xC8 (CP_START)\n");

	mif_info("send 0xC1 (INIT_START)\n");
	dpld->send_intr(dpld, INT_CMD(INT_CMD_INIT_START));

	dpld->reset_dpram_ipc(dpld);

	iod = link_get_iod_with_format(ld, IPC_FMT);
	if (!iod) {
		mif_err("ERR! no iod\n");
		return;
	}
	iod->modem_state_changed(iod, STATE_ONLINE);

	mif_info("send 0xC2 (INIT_END)\n");
	dpld->send_intr(dpld, INT_CMD(INT_CMD_INIT_END));
}
Ejemplo n.º 12
0
static void usb_rx_complete(struct urb *urb)
{
	struct if_usb_devdata *pipe_data = urb->context;
	struct usb_link_device *usb_ld = usb_get_intfdata(pipe_data->data_intf);
	struct io_device *iod;
	int iod_format = IPC_FMT;
	int ret;

	usb_mark_last_busy(urb->dev);

	switch (urb->status) {
	case 0:
	case -ENOENT:
		if (!urb->actual_length)
			goto re_submit;
		/* call iod recv */
		/* how we can distinguish boot ch with fmt ch ?? */
		switch (pipe_data->format) {
		case IF_USB_FMT_EP:
			iod_format = IPC_FMT;
			pr_buffer("rx", (char *)urb->transfer_buffer,
					(size_t)urb->actual_length, 16);
			break;
		case IF_USB_RAW_EP:
			iod_format = IPC_MULTI_RAW;
			break;
		case IF_USB_RFS_EP:
			iod_format = IPC_RFS;
			break;
		default:
			break;
		}

		/* during boot stage fmt end point */
		/* shared with boot io device */
		/* when we use fmt device only, at boot and ipc exchange
			it can be reduced to 1 device */
		if (iod_format == IPC_FMT &&
			usb_ld->ld.com_state == COM_BOOT)
			iod_format = IPC_BOOT;
		if (iod_format == IPC_FMT &&
			usb_ld->ld.com_state == COM_CRASH)
			iod_format = IPC_RAMDUMP;

		iod = link_get_iod_with_format(&usb_ld->ld, iod_format);
		if (iod) {
			ret = iod->recv(iod,
					&usb_ld->ld,
					(char *)urb->transfer_buffer,
					urb->actual_length);
			if (ret < 0)
				mif_err("io device recv error :%d\n", ret);
		}
re_submit:
		if (urb->status || atomic_read(&usb_ld->suspend_count))
			break;

		usb_mark_last_busy(urb->dev);
		usb_rx_submit(pipe_data, urb, GFP_ATOMIC);
		return;
	case -ESHUTDOWN:
	case -EPROTO:
		break;
	case -EOVERFLOW:
		mif_err("RX overflow\n");
		break;
	default:
		mif_err("RX complete Status (%d)\n", urb->status);
		break;
	}

	usb_anchor_urb(urb, &pipe_data->urbs);
}
Ejemplo n.º 13
0
static void usb_rx_complete(struct urb *urb)
{
	struct if_usb_devdata *pipe_data = urb->context;
	struct usb_link_device *usb_ld = pipe_data->usb_ld;
	struct io_device *iod;
	int iod_format;
	int ret;

	if (usb_ld->usbdev)
		usb_mark_last_busy(usb_ld->usbdev);

	switch (urb->status) {
	case -ENOENT:
		/* case for 'link pm suspended but rx data had remained' */
		mif_debug("urb->status = -ENOENT\n");
	case 0:
		if (!urb->actual_length) {
			mif_debug("urb has zero length!\n");
			goto rx_submit;
		}

		usb_ld->link_pm_data->rx_cnt++;
		/* call iod recv */
		/* how we can distinguish boot ch with fmt ch ?? */
		switch (pipe_data->format) {
		case IF_USB_FMT_EP:
			if (usb_ld->if_usb_is_main) {
				//pr_urb("IPC-RX", urb);
				iod_format = IPC_FMT;
			} else {
				iod_format = IPC_BOOT;
			}
			break;
		case IF_USB_RAW_EP:
			iod_format = IPC_MULTI_RAW;
			break;
		case IF_USB_RFS_EP:
			iod_format = IPC_RFS;
			break;
		case IF_USB_CMD_EP:
			iod_format = IPC_CMD;
			break;
		default:
			iod_format = -1;
			break;
		}

		/* flow control CMD by CP, not use io device */
		if (unlikely(iod_format == IPC_CMD)) {
			ret = link_rx_flowctl_cmd(&usb_ld->ld,
					(char *)urb->transfer_buffer,
					urb->actual_length);
			if (ret < 0)
				mif_err("no multi raw device (%d)\n", ret);
			goto rx_submit;
		}

		iod = link_get_iod_with_format(&usb_ld->ld, iod_format);
		if (iod) {
			ret = iod->recv(iod,
					&usb_ld->ld,
					(char *)urb->transfer_buffer,
					urb->actual_length);
			if (ret == -ENOMEM) {
				/* retry the delay work and resubit*/
				mif_err("ENOMEM, retry\n");
				if (usb_ld->usbdev)
					usb_mark_last_busy(usb_ld->usbdev);
				usb_ld->retry_urb = urb;
				queue_delayed_work(usb_ld->ld.tx_wq,
					&usb_ld->rx_retry_work, 0);
				return;
			}
			if (ret < 0)
				mif_err("io device recv error (%d)\n", ret);
		}
rx_submit:
		if (urb->status == 0) {
			if (usb_ld->usbdev)
				usb_mark_last_busy(usb_ld->usbdev);
			usb_rx_submit(usb_ld, pipe_data, GFP_ATOMIC);
		}
		break;
	default:
		mif_err("urb err status = %d\n", urb->status);
		break;
	}
}
Ejemplo n.º 14
0
static void usb_rx_retry_work(struct work_struct *work)
{
	int ret = 0;
	struct usb_link_device *usb_ld =
		container_of(work, struct usb_link_device, rx_retry_work.work);
	struct urb *urb = usb_ld->retry_urb;
	struct if_usb_devdata *pipe_data = urb->context;
	struct io_device *iod;
	int iod_format;

	if (!usb_ld->if_usb_connected || !usb_ld->usbdev)
		return;

	if (usb_ld->usbdev)
		usb_mark_last_busy(usb_ld->usbdev);
	switch (pipe_data->format) {
	case IF_USB_FMT_EP:
		if (usb_ld->if_usb_is_main) {
			pr_urb("IPC-RX, retry", urb);
			iod_format = IPC_FMT;
		} else {
			iod_format = IPC_BOOT;
		}
		break;
	case IF_USB_RAW_EP:
		iod_format = IPC_MULTI_RAW;
		break;
	case IF_USB_RFS_EP:
		iod_format = IPC_RFS;
		pr_urb("RFS-RX, retry", urb);
		break;
	case IF_USB_CMD_EP:
		iod_format = IPC_CMD;
		break;
	default:
		iod_format = -1;
		break;
	}

	iod = link_get_iod_with_format(&usb_ld->ld, iod_format);
	if (iod) {
		ret = iod->recv(iod, &usb_ld->ld, (char *)urb->transfer_buffer,
			urb->actual_length);
		if (ret == -ENOMEM) {
			/* TODO: check the retry count */
			/* retry the delay work after 20ms and resubit*/
			mif_err("ENOMEM, +retry 20ms\n");
			if (usb_ld->usbdev)
				usb_mark_last_busy(usb_ld->usbdev);
			usb_ld->retry_urb = urb;
			if (usb_ld->rx_retry_cnt++ < 10)
				queue_delayed_work(usb_ld->ld.tx_wq,
					&usb_ld->rx_retry_work,	10);
			return;
		}
		if (ret < 0)
			mif_err("io device recv error (%d)\n", ret);
		usb_ld->rx_retry_cnt = 0;
	}

	if (usb_ld->usbdev)
		usb_mark_last_busy(usb_ld->usbdev);
	usb_rx_submit(usb_ld, pipe_data, GFP_ATOMIC);
}