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; }
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); }
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; }
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; }
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; }
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); }
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; } } } }
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; }
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; }
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); }
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; }