Beispiel #1
0
static int hsic_send(struct link_device *ld, struct io_device *iod,
							struct sk_buff *skb)
{
	int ret, rpm_state;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct link_pm_data *pm_data = usb_ld->link_pm_data;

	if (!usb_ld->if_usb_connected)
		goto link_disconnect;

	/* delay for net channel, limited by xmm6260 capacity */
	if (iod->send_delay && (iod->io_typ == IODEV_NET) \
			&& (1400 == skb->len))
		udelay(iod->send_delay);

	rpm_state = hsic_pm_runtime_get_active_async(pm_data);
	if (rpm_state == -ENODEV)
		goto link_disconnect;

	pm_runtime_get_noresume(&usb_ld->usbdev->dev);

	ret = hsic_tx_skb(&usb_ld->devdata[iod->id], skb);

	usb_mark_last_busy(usb_ld->usbdev);
	pm_runtime_put(&usb_ld->usbdev->dev);

	return ret;

link_disconnect:
	if (iod->io_typ != IODEV_NET)
		report_modem_state(ld, MODEM_EVENT_DISCONN);
	return -EINVAL;
}
Beispiel #2
0
static void hsic_tx_complete(struct urb *urb)
{
	struct sk_buff *skb = urb->context;
	struct io_device *iod = skbpriv(skb)->iod;
	struct link_device *linkdev = get_current_link(iod);
	struct usb_link_device *usb_ld = to_usb_link_device(linkdev);

	switch (urb->status) {
	case 0:
		if (urb->actual_length != urb->transfer_buffer_length)
			MIF_ERR("TX len=%d, Complete len=%d\n",
				urb->transfer_buffer_length, urb->actual_length);
		break;
	case -ECONNRESET:
		if (urb->actual_length)
			MIF_ERR("ECONNRESET: TX len=%d, Complete len=%d\n",
				urb->transfer_buffer_length, urb->actual_length);
	case -ENOENT:
	case -ESHUTDOWN:
	default:
		MIF_ERR("iod %d TX error (%d)\n", iod->id, urb->status);
	}

	if (iod->atdebug && iod->atdebugfunc)
		iod->atdebugfunc(iod, skb->data, skb->len);

	dev_kfree_skb_any(skb);
	usb_free_urb(urb);

	if (urb->dev && usb_ld->if_usb_connected)
		usb_mark_last_busy(urb->dev);
}
Beispiel #3
0
static int usb_send(struct link_device *ld, struct io_device *iod,
			struct sk_buff *skb)
{
	struct sk_buff_head *txq;
	size_t tx_size;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct link_pm_data *pm_data = usb_ld->link_pm_data;

	switch (iod->format) {
	case IPC_RAW:
		txq = &ld->sk_raw_tx_q;

		if (unlikely(ld->raw_tx_suspended)) {
			/* Unlike misc_write, vnet_xmit is in interrupt.
			 * Despite call netif_stop_queue on CMD_SUSPEND,
			 * packets can be reached here.
			 */
			if (in_irq()) {
				mif_err("raw tx is suspended, "
						"drop packet. size=%d",
						skb->len);
				return -EBUSY;
			}

			mif_err("wait RESUME CMD...\n");
			INIT_COMPLETION(ld->raw_tx_resumed_by_cp);
			wait_for_completion(&ld->raw_tx_resumed_by_cp);
			mif_err("resumed done.\n");
		}
		break;
	case IPC_BOOT:
	case IPC_FMT:
	case IPC_RFS:
	default:
		txq = &ld->sk_fmt_tx_q;
		break;
	}
	/* store the tx size before run the tx_delayed_work*/
	tx_size = skb->len;

	/* drop packet, when link is not online */
	if (ld->com_state == COM_BOOT && iod->format != IPC_BOOT) {
		mif_err("%s: drop packet, size=%d, com_state=%d\n",
				iod->name, skb->len, ld->com_state);
		dev_kfree_skb_any(skb);
		return 0;
	}

	/* en queue skb data */
	skb_queue_tail(txq, skb);
	/* Hold wake_lock for getting schedule the tx_work */
	wake_lock(&pm_data->tx_async_wake);

	if (!work_pending(&ld->tx_delayed_work.work))
		queue_delayed_work(ld->tx_wq, &ld->tx_delayed_work, 0);

	return tx_size;
}
Beispiel #4
0
static int start_ipc(struct link_device *ld, struct io_device *iod)
{
	struct sk_buff *skb;
	char data[1] = {'a'};
	int err;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct if_usb_devdata *pipe_data = &usb_ld->devdata[IF_USB_FMT_EP];

	mif_err("\n");

	if (usb_ld->link_pm_data->hub_handshake_done) {
		mif_err("Aleady send start ipc, skip start ipc\n");
		err = 0;
		goto exit;
	}

	if (!usb_ld->if_usb_connected) {
		mif_err("HSIC/USB not connected, skip start ipc\n");
		err = -ENODEV;
		goto exit;
	}

	if (usb_ld->if_usb_initstates == INIT_IPC_START_DONE) {
		mif_debug("aleady IPC started\n");
		err = 0;
		goto exit;
	}

	mif_info("send 'a'\n");

	skb = alloc_skb(16, GFP_ATOMIC);
	if (unlikely(!skb))
		return -ENOMEM;
	memcpy(skb_put(skb, 1), data, 1);

	skbpriv(skb)->iod = iod;
	skbpriv(skb)->ld = &usb_ld->ld;
	err = usb_tx_urb_with_skb(usb_ld, skb, pipe_data);
	if (err < 0) {
		mif_err("usb_tx_urb fail\n");
		goto exit;
	}
	usb_ld->link_pm_data->hub_handshake_done = true;
	usb_ld->if_usb_initstates = INIT_IPC_START_DONE;
exit:
	return err;
}
Beispiel #5
0
static int usb_send(struct link_device *ld, struct io_device *iod,
			struct sk_buff *skb)
{
	struct sk_buff_head *txq;
	size_t tx_size;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct link_pm_data *pm_data = usb_ld->link_pm_data;

	switch (iod->format) {
	case IPC_RAW:
		txq = &ld->sk_raw_tx_q;

		if (unlikely(ld->raw_tx_suspended)) {
			mif_err("wait RESUME CMD...\n");
			INIT_COMPLETION(ld->raw_tx_resumed_by_cp);
			wait_for_completion(&ld->raw_tx_resumed_by_cp);
			mif_err("resumed done.\n");
		}
		break;
	case IPC_BOOT:
	case IPC_FMT:
	case IPC_RFS:
	default:
		txq = &ld->sk_fmt_tx_q;
		/* Hold wake_lock for getting schedule the tx_work */
		wake_lock(&pm_data->tx_async_wake);
		break;
	}
	/* store the tx size before run the tx_delayed_work*/
	tx_size = skb->len;

	/* drop packet, when link is not online */
	if (ld->com_state == COM_BOOT && iod->format != IPC_BOOT) {
		mif_err("%s: drop packet, size=%d, com_state=%d\n",
				iod->name, skb->len, ld->com_state);
		return -ENODEV;
	}

	/* en queue skb data */
	skb_queue_tail(txq, skb);

	if (!work_pending(&ld->tx_delayed_work.work))
		queue_delayed_work(ld->tx_wq, &ld->tx_delayed_work, 0);

	return tx_size;
}
static int start_ipc(struct link_device *ld, struct io_device *iod)
{
	struct sk_buff *skb;
	char data[1] = {'a'};
	int err;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct if_usb_devdata *pipe_data = &usb_ld->devdata[IF_USB_FMT_EP];

	if (!usb_ld->if_usb_connected) {
		mif_err("HSIC not connected, skip start ipc\n");
		err = -ENODEV;
		goto exit;
	}

	if (ld->mc->phone_state != STATE_ONLINE) {
		mif_err("[MODEM_IF] MODEM is not online, skip start ipc\n");
		err = -ENODEV;
		goto exit;
	}

	mif_err("send 'a'\n");

	skb = alloc_skb(16, GFP_ATOMIC);
	if (unlikely(!skb))
		return -ENOMEM;
	memcpy(skb_put(skb, 1), data, 1);
	skbpriv(skb)->iod = iod;
	skbpriv(skb)->ld = ld;

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

	usb_mark_last_busy(usb_ld->usbdev);
	err = usb_tx_urb_with_skb(usb_ld->usbdev, skb, pipe_data);
	if (err < 0) {
		mif_err("usb_tx_urb fail\n");
		dev_kfree_skb_any(skb);
		goto exit;
	}
exit:
	return err;
}
Beispiel #7
0
static int _usb_tx_work(struct sk_buff *skb)
{
	struct sk_buff_head *txq;
	struct io_device *iod = skbpriv(skb)->iod;
	struct link_device *ld = skbpriv(skb)->ld;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct if_usb_devdata *pipe_data;

	switch (iod->format) {
	case IPC_BOOT:
	case IPC_FMT:
		/* boot device uses same intf with fmt*/
		pipe_data = &usb_ld->devdata[IF_USB_FMT_EP];
		txq = &ld->sk_fmt_tx_q;
		break;
	case IPC_RAW:
		pipe_data = &usb_ld->devdata[IF_USB_RAW_EP];
		txq = &ld->sk_raw_tx_q;
		break;
	case IPC_RFS:
		pipe_data = &usb_ld->devdata[IF_USB_RFS_EP];
		txq = &ld->sk_fmt_tx_q;
		break;
	default:
		/* wrong packet, drop it */
		pipe_data =  NULL;
		txq = NULL;
		break;
	}

	if (!pipe_data)
		return -ENOENT;

#if 0
	if (iod->format == IPC_FMT && usb_ld->if_usb_is_main)
		pr_skb("IPC-TX", skb);
#endif
	if (iod->format == IPC_RAW)
		mif_debug("TX[RAW]\n");

	return usb_tx_urb_with_skb(usb_ld->usbdev, skb,	pipe_data);
}
Beispiel #8
0
static void usb_tx_complete(struct urb *urb)
{
	struct sk_buff *skb = urb->context;
	struct io_device *iod = skbpriv(skb)->iod;
	struct link_device *ld = skbpriv(skb)->ld;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);

	switch (urb->status) {
	case 0:
		break;
	case -ENOENT:
	case -ECONNRESET:
	case -ESHUTDOWN:
	default:
		if (iod->format != IPC_BOOT)
			mif_info("TX error (%d)\n", urb->status);
	}

	dev_kfree_skb_any(skb);
	if (urb->dev && usb_ld->if_usb_connected)
		usb_mark_last_busy(urb->dev);
	usb_free_urb(urb);
}
static void usb_tx_work(struct work_struct *work)
{
	int ret = 0;
	struct link_device *ld =
		container_of(work, struct link_device, tx_delayed_work.work);
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct io_device *iod;
	struct sk_buff *skb;
	struct if_usb_devdata *pipe_data;
	struct link_pm_data *pm_data = usb_ld->link_pm_data;

	/*TODO: check the PHONE ACTIVE STATES */
	/* because tx data wait until hub on with wait_for_complettion, it
	 should queue to single_threaded work queue */
	if (!link_pm_set_active(usb_ld))
		return;

	while (ld->sk_fmt_tx_q.qlen || ld->sk_raw_tx_q.qlen) {
		/* send skb from fmt_txq and raw_txq,
		 * one by one for fair flow control */
		skb = skb_dequeue(&ld->sk_fmt_tx_q);
		if (skb) {
			iod = skbpriv(skb)->iod;
			switch (iod->format) {
			case IPC_BOOT:
			case IPC_RAMDUMP:
			case IPC_FMT:
				/* boot device uses same intf with fmt*/
				pipe_data = &usb_ld->devdata[IF_USB_FMT_EP];
				break;
			case IPC_RFS:
				pipe_data = &usb_ld->devdata[IF_USB_RFS_EP];
				break;
			default:
				/* wrong packet for fmt tx q , drop it */
				dev_kfree_skb_any(skb);
				continue;
			}

			ret = usb_tx_urb_with_skb(usb_ld, skb, pipe_data);
			if (ret < 0) {
				mif_err("usb_tx_urb_with_skb, ret(%d)\n",
					ret);
				skb_queue_head(&ld->sk_fmt_tx_q, skb);
				return;
			}
		}

		skb = skb_dequeue(&ld->sk_raw_tx_q);
		if (skb) {
			pipe_data = &usb_ld->devdata[IF_USB_RAW_EP];
			ret = usb_tx_urb_with_skb(usb_ld, skb, pipe_data);
			if (ret < 0) {
				mif_err("usb_tx_urb_with_skb "
						"for raw, ret(%d)\n",
						ret);
				skb_queue_head(&ld->sk_raw_tx_q, skb);
				return;
			}
		}
	}
}
Beispiel #10
0
static void usb_tx_work(struct work_struct *work)
{
	int ret = 0;
	struct link_device *ld =
		container_of(work, struct link_device, tx_delayed_work.work);
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct sk_buff *skb;
	struct link_pm_data *pm_data = usb_ld->link_pm_data;

	if (!usb_ld->usbdev) {
		mif_info("usbdev is invalid\n");
		return;
	}

	pm_data->tx_cnt++;

	while (ld->sk_fmt_tx_q.qlen || ld->sk_raw_tx_q.qlen) {
		/* request and check usb runtime pm first */
		ret = link_pm_runtime_get_active(pm_data);
		if (ret < 0) {
			if (ret == -ENODEV) {
				mif_err("link not avail, retry reconnect.\n");
				goto exit;
			}
			goto retry_tx_work;
		}

		/* If AP try to tx when interface disconnect->reconnect probe,
		 * usbdev was created but one of interface channel device are
		 * probing, _usb_tx_work return to -ENOENT then runtime usage
		 * count allways positive and never enter to L2
		 */
		if (!usb_ld->if_usb_connected) {
			mif_info("link is available, but if  was not readey\n");
			goto retry_tx_work;
		}
		pm_runtime_get_sync(&usb_ld->usbdev->dev);

		ret = 0;
		/* send skb from fmt_txq and raw_txq,*/
		/* one by one for fair flow control */
		skb = skb_dequeue(&ld->sk_fmt_tx_q);
		if (skb)
			ret = _usb_tx_work(skb);

		if (ret) {
			mif_err("usb_tx_urb_with_skb for fmt_q %d\n", ret);
			skb_queue_head(&ld->sk_fmt_tx_q, skb);

			if (ret == -ENODEV || ret == -ENOENT)
				goto exit;

			/* tx fail and usbdev alived, retry tx work */
			pm_runtime_put(&usb_ld->usbdev->dev);
			goto retry_tx_work;
		}

		skb = skb_dequeue(&ld->sk_raw_tx_q);
		if (skb)
			ret = _usb_tx_work(skb);

		if (ret) {
			mif_err("usb_tx_urb_with_skb for raw_q %d\n", ret);
			skb_queue_head(&ld->sk_raw_tx_q, skb);

			if (ret == -ENODEV || ret == -ENOENT)
				goto exit;

			pm_runtime_put(&usb_ld->usbdev->dev);
			goto retry_tx_work;
		}

		pm_runtime_put(&usb_ld->usbdev->dev);
	}
	wake_unlock(&pm_data->tx_async_wake);
exit:
	return;

retry_tx_work:
	queue_delayed_work(ld->tx_wq, &ld->tx_delayed_work,
		msecs_to_jiffies(20));
	return;
}
Beispiel #11
0
static int start_ipc(struct link_device *ld, struct io_device *iod)
{
	struct sk_buff *skb;
	char data[1] = {'a'};
	int err;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct link_pm_data *pm_data = usb_ld->link_pm_data;
	struct device *dev = &usb_ld->usbdev->dev;
	struct if_usb_devdata *pipe_data = &usb_ld->devdata[IF_USB_FMT_EP];

	if (!usb_ld->if_usb_connected) {
		mif_err("HSIC not connected, skip start ipc\n");
		err = -ENODEV;
		goto exit;
	}

retry:
	if (ld->mc->phone_state != STATE_ONLINE) {
		mif_err("MODEM is not online, skip start ipc\n");
		err = -ENODEV;
		goto exit;
	}

	/* check usb runtime pm first */
	if (dev->power.runtime_status != RPM_ACTIVE) {
		if (!pm_data->resume_requested) {
			mif_debug("QW PM\n");
			INIT_COMPLETION(pm_data->active_done);
			queue_delayed_work(pm_data->wq,
					&pm_data->link_pm_work, 0);
		}
		mif_debug("Wait pm\n");
		err = wait_for_completion_timeout(&pm_data->active_done,
							msecs_to_jiffies(500));
		/* timeout or -ERESTARTSYS */
		if (err <= 0)
			goto retry;
	}

	pm_runtime_get_sync(dev);

	mif_err("send 'a'\n");

	skb = alloc_skb(16, GFP_ATOMIC);
	if (unlikely(!skb)) {
		pm_runtime_put(dev);
		return -ENOMEM;
	}
	memcpy(skb_put(skb, 1), data, 1);
	skbpriv(skb)->iod = iod;
	skbpriv(skb)->ld = ld;

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

	usb_mark_last_busy(usb_ld->usbdev);
	err = usb_tx_urb_with_skb(usb_ld->usbdev, skb, pipe_data);
	if (err < 0) {
		mif_err("usb_tx_urb fail\n");
		dev_kfree_skb_any(skb);
	}

	pm_runtime_put(dev);
exit:
	return err;
}
Beispiel #12
0
static void usb_tx_work(struct work_struct *work)
{
	int ret = 0;
	struct link_device *ld =
		container_of(work, struct link_device, tx_delayed_work.work);
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct sk_buff *skb;
	struct link_pm_data *pm_data = usb_ld->link_pm_data;

	if (!usb_ld->usbdev) {
		mif_info("usbdev is invalid\n");
		return;
	}

	while (ld->sk_fmt_tx_q.qlen || ld->sk_raw_tx_q.qlen) {
		/* request and check usb runtime pm first */
		ret = link_pm_runtime_get_active(pm_data);
		if (ret < 0) {
			if (ret == -ENODEV)
				mif_err("link not avail, retry reconnect.\n");
			else
				queue_delayed_work(ld->tx_wq,
				&ld->tx_delayed_work, msecs_to_jiffies(20));
			return;
		}

		usb_mark_last_busy(usb_ld->usbdev);
		pm_runtime_get_sync(&usb_ld->usbdev->dev);

		ret = 0;
		/* send skb from fmt_txq and raw_txq,*/
		/* one by one for fair flow control */
		skb = skb_dequeue(&ld->sk_fmt_tx_q);
		if (skb)
			ret = _usb_tx_work(skb);

		if (ret) {
			if (ret != -ENODEV && ret != -ENOENT)
				pm_runtime_put(&usb_ld->usbdev->dev);
			/* Do not call runtime_put if ret is ENODEV. Unless it
			 * will invoke bugs */
			else
				skb_queue_head(&ld->sk_fmt_tx_q, skb);
			return;
		}

		skb = skb_dequeue(&ld->sk_raw_tx_q);
		if (skb)
			ret = _usb_tx_work(skb);

		if (ret) {
			if (ret != -ENODEV && ret != -ENOENT)
				pm_runtime_put(&usb_ld->usbdev->dev);
			else
				skb_queue_head(&ld->sk_raw_tx_q, skb);
			return;
		}

		pm_runtime_put(&usb_ld->usbdev->dev);
		usb_mark_last_busy(usb_ld->usbdev);
	}
	wake_unlock(&pm_data->tx_async_wake);
}
Beispiel #13
0
static int _usb_tx_work(struct sk_buff *skb)
{
	struct sk_buff_head *txq;
	struct io_device *iod = skbpriv(skb)->iod;
	struct link_device *ld = skbpriv(skb)->ld;
	struct usb_link_device *usb_ld = to_usb_link_device(ld);
	struct if_usb_devdata *pipe_data;
	int ret;

	switch (iod->format) {
	case IPC_BOOT:
	case IPC_FMT:
		/* boot device uses same intf with fmt*/
		pipe_data = &usb_ld->devdata[IF_USB_FMT_EP];
		txq = &ld->sk_fmt_tx_q;
		break;
	case IPC_RAW:
		pipe_data = &usb_ld->devdata[IF_USB_RAW_EP];
		txq = &ld->sk_raw_tx_q;
		break;
	case IPC_RFS:
		pipe_data = &usb_ld->devdata[IF_USB_RFS_EP];
		txq = &ld->sk_fmt_tx_q;
		break;
	default:
		/* wrong packet, drop it */
		pipe_data =  NULL;
		break;
	}

	if (!pipe_data) {
		dev_kfree_skb_any(skb);
		return -ENOENT;
	}

	if (iod->format == IPC_FMT && usb_ld->if_usb_is_main)
		pr_skb("IPC-TX", skb);

	if (iod->format == IPC_RAW)
		mif_debug("TX[RAW]\n");

	if (iod->format == IPC_RFS)
		pr_skb("RFS-TX", skb);

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

	usb_mark_last_busy(usb_ld->usbdev);
	ret = usb_tx_urb_with_skb(usb_ld->usbdev,
				skb,
				pipe_data);
	if (ret < 0) {
		if (ret == -ENODEV || ret == -ENOENT) {
			mif_err("link broken while in runtime active ..."
					" purge!\n");
			return ret;
		}
		mif_err("usb_tx_urb_with_skb for iod(%d), ret=%d\n",
				iod->format, ret);
		skb_queue_head(txq, skb);
		queue_delayed_work(ld->tx_wq,
				&ld->tx_delayed_work,
				msecs_to_jiffies(20));
		return ret;
	}

	return 0;
}