diff options
Diffstat (limited to 'drivers/usb/misc/mdm_data_bridge.c')
-rw-r--r-- | drivers/usb/misc/mdm_data_bridge.c | 71 |
1 files changed, 65 insertions, 6 deletions
diff --git a/drivers/usb/misc/mdm_data_bridge.c b/drivers/usb/misc/mdm_data_bridge.c index 6af9664..2dedc6d 100644 --- a/drivers/usb/misc/mdm_data_bridge.c +++ b/drivers/usb/misc/mdm_data_bridge.c @@ -20,6 +20,10 @@ #include <linux/uaccess.h> #include <linux/ratelimit.h> #include <mach/usb_bridge.h> +#ifdef CONFIG_MDM_HSIC_PM +#include <linux/mdm_hsic_pm.h> +static const char rmnet_pm_dev[] = "mdm_hsic_pm0"; +#endif #define MAX_RX_URBS 50 #define RMNET_RX_BUFSIZE 2048 @@ -117,7 +121,17 @@ static inline bool rx_halted(struct data_bridge *dev) static inline bool rx_throttled(struct bridge *brdg) { +#ifndef CONFIG_MDM_HSIC_PM return test_bit(RX_THROTTLED, &brdg->flags); +#else + /* if the bridge is open or not, resume to consume mdm request + * because this link is not dead, it's alive + */ + if (brdg) + return test_bit(RX_THROTTLED, &brdg->flags); + else + return 0; +#endif } int data_bridge_unthrottle_rx(unsigned int id) @@ -149,11 +163,26 @@ static void data_bridge_process_rx(struct work_struct *work) container_of(work, struct data_bridge, process_rx_w); struct bridge *brdg = dev->brdg; - +#if !defined(CONFIG_MDM_HSIC_PM) + /* if the bridge is open or not, resume to consume mdm request + * because this link is not dead, it's alive + */ if (!brdg || !brdg->ops.send_pkt || rx_halted(dev)) return; +#endif while (!rx_throttled(brdg) && (skb = skb_dequeue(&dev->rx_done))) { +#ifdef CONFIG_MDM_HSIC_PM + /* if the bridge is open or not, resume to consume mdm request + * because this link is not dead, it's alive + */ + if (!brdg) { + print_hex_dump(KERN_INFO, "dun:", 0, 1, 1, skb->data, + skb->len, false); + dev_kfree_skb_any(skb); + continue; + } +#endif dev->to_host++; info = (struct timestamp_info *)skb->cb; info->rx_done_sent = get_timestamp(); @@ -197,12 +226,18 @@ static void data_bridge_read_cb(struct urb *urb) skb_put(skb, urb->actual_length); switch (urb->status) { + case -ENOENT: /* suspended */ case 0: /* success */ queue = 1; info->rx_done = get_timestamp(); spin_lock(&dev->rx_done.lock); __skb_queue_tail(&dev->rx_done, skb); spin_unlock(&dev->rx_done.lock); +#ifdef CONFIG_MDM_HSIC_PM + /* wakelock for fast dormancy */ + if (urb->actual_length) + fast_dormancy_wakelock(rmnet_pm_dev); +#endif break; /*do not resubmit*/ @@ -212,7 +247,6 @@ static void data_bridge_read_cb(struct urb *urb) schedule_work(&dev->kevent); /* FALLTHROUGH */ case -ESHUTDOWN: - case -ENOENT: /* suspended */ case -ECONNRESET: /* unplug */ case -EPROTO: dev_kfree_skb_any(skb); @@ -229,9 +263,14 @@ static void data_bridge_read_cb(struct urb *urb) } spin_lock(&dev->rx_done.lock); + urb->context = NULL; list_add_tail(&urb->urb_list, &dev->rx_idle); spin_unlock(&dev->rx_done.lock); + /* during suspend handle rx packet, but do not queue rx work */ + if (urb->status == -ENOENT) + return; + if (queue) queue_work(dev->wq, &dev->process_rx_w); } @@ -266,6 +305,7 @@ static int submit_rx_urb(struct data_bridge *dev, struct urb *rx_urb, if (retval) goto fail; + usb_mark_last_busy(dev->udev); return 0; fail: usb_unanchor_urb(rx_urb); @@ -320,9 +360,9 @@ int data_bridge_open(struct bridge *brdg) dev->tx_unthrottled_cnt = 0; dev->rx_throttled_cnt = 0; dev->rx_unthrottled_cnt = 0; - +#ifndef CONFIG_MDM_HSIC_PM queue_work(dev->wq, &dev->process_rx_w); - +#endif return 0; } EXPORT_SYMBOL(data_bridge_open); @@ -563,8 +603,12 @@ static int data_bridge_resume(struct data_bridge *dev) dev->to_modem++; dev->txurb_drp_cnt--; } - + /* if the bridge is open or not, resume to consume mdm request + * because this link is not dead, it's alive + */ +#ifndef CONFIG_MDM_HSIC_PM if (dev->brdg) +#endif queue_work(dev->wq, &dev->process_rx_w); return 0; @@ -662,7 +706,12 @@ static int data_bridge_probe(struct usb_interface *iface, /*allocate list of rx urbs*/ data_bridge_prepare_rx(dev); - +#ifdef CONFIG_MDM_HSIC_PM + /* if the bridge is open or not, resume to consume mdm request + * because this link is not dead, it's alive + */ + queue_work(dev->wq, &dev->process_rx_w); +#endif platform_device_add(dev->pdev); return 0; @@ -979,6 +1028,7 @@ static void bridge_disconnect(struct usb_interface *intf) struct data_bridge *dev = usb_get_intfdata(intf); struct list_head *head; struct urb *rx_urb; + struct sk_buff *skb; unsigned long flags; if (!dev) { @@ -995,12 +1045,20 @@ static void bridge_disconnect(struct usb_interface *intf) cancel_work_sync(&dev->process_rx_w); cancel_work_sync(&dev->kevent); + spin_lock_irqsave(&dev->rx_done.lock, flags); + while ((skb = __skb_dequeue(&dev->rx_done))) + dev_kfree_skb_any(skb); + spin_unlock_irqrestore(&dev->rx_done.lock, flags); + /*free rx urbs*/ head = &dev->rx_idle; spin_lock_irqsave(&dev->rx_done.lock, flags); while (!list_empty(head)) { rx_urb = list_entry(head->next, struct urb, urb_list); list_del(&rx_urb->urb_list); + skb = (struct sk_buff *)rx_urb->context; + if (skb) + dev_kfree_skb_any(skb); usb_free_urb(rx_urb); } spin_unlock_irqrestore(&dev->rx_done.lock, flags); @@ -1040,6 +1098,7 @@ static struct usb_driver bridge_driver = { .id_table = bridge_ids, .suspend = bridge_suspend, .resume = bridge_resume, + .reset_resume = bridge_resume, .supports_autosuspend = 1, }; |