aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/misc/mdm_data_bridge.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/misc/mdm_data_bridge.c')
-rw-r--r--drivers/usb/misc/mdm_data_bridge.c71
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,
};