Merge "usb: gadget: purge pending responses upon rmnet suspend"
diff --git a/drivers/usb/gadget/f_rmnet.c b/drivers/usb/gadget/f_rmnet.c
index 4a455b6..e6613e8 100644
--- a/drivers/usb/gadget/f_rmnet.c
+++ b/drivers/usb/gadget/f_rmnet.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -539,6 +539,25 @@
kfree(f->name);
}
+static void frmnet_purge_responses(struct f_rmnet *dev)
+{
+ unsigned long flags;
+ struct rmnet_ctrl_pkt *cpkt;
+
+ pr_debug("%s: port#%d\n", __func__, dev->port_num);
+
+ spin_lock_irqsave(&dev->lock, flags);
+ while (!list_empty(&dev->cpkt_resp_q)) {
+ cpkt = list_first_entry(&dev->cpkt_resp_q,
+ struct rmnet_ctrl_pkt, list);
+
+ list_del(&cpkt->list);
+ rmnet_free_ctrl_pkt(cpkt);
+ }
+ atomic_set(&dev->notify_count, 0);
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
static void frmnet_suspend(struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
@@ -549,6 +568,8 @@
__func__, xport_to_str(dxport),
dev, dev->port_num);
+ frmnet_purge_responses(dev);
+
port_num = rmnet_ports[dev->port_num].data_xport_num;
switch (dxport) {
case USB_GADGET_XPORT_BAM:
@@ -602,8 +623,6 @@
static void frmnet_disable(struct usb_function *f)
{
struct f_rmnet *dev = func_to_rmnet(f);
- unsigned long flags;
- struct rmnet_ctrl_pkt *cpkt;
pr_debug("%s: port#%d\n", __func__, dev->port_num);
@@ -612,16 +631,7 @@
atomic_set(&dev->online, 0);
- spin_lock_irqsave(&dev->lock, flags);
- while (!list_empty(&dev->cpkt_resp_q)) {
- cpkt = list_first_entry(&dev->cpkt_resp_q,
- struct rmnet_ctrl_pkt, list);
-
- list_del(&cpkt->list);
- rmnet_free_ctrl_pkt(cpkt);
- }
- atomic_set(&dev->notify_count, 0);
- spin_unlock_irqrestore(&dev->lock, flags);
+ frmnet_purge_responses(dev);
gport_rmnet_disconnect(dev);
}
@@ -709,11 +719,11 @@
ret = usb_ep_queue(dev->notify, dev->notify_req, GFP_ATOMIC);
if (ret) {
- atomic_dec(&dev->notify_count);
spin_lock_irqsave(&dev->lock, flags);
- cpkt = list_first_entry(&dev->cpkt_resp_q,
+ if (!list_empty(&dev->cpkt_resp_q)) {
+ atomic_dec(&dev->notify_count);
+ cpkt = list_first_entry(&dev->cpkt_resp_q,
struct rmnet_ctrl_pkt, list);
- if (cpkt) {
list_del(&cpkt->list);
rmnet_free_ctrl_pkt(cpkt);
}
@@ -739,10 +749,8 @@
static void frmnet_disconnect(struct grmnet *gr)
{
struct f_rmnet *dev;
- unsigned long flags;
struct usb_cdc_notification *event;
int status;
- struct rmnet_ctrl_pkt *cpkt;
if (!gr) {
pr_err("%s: Invalid grmnet:%p\n", __func__, gr);
@@ -776,17 +784,7 @@
__func__, status);
}
- spin_lock_irqsave(&dev->lock, flags);
- while (!list_empty(&dev->cpkt_resp_q)) {
- cpkt = list_first_entry(&dev->cpkt_resp_q,
- struct rmnet_ctrl_pkt, list);
-
- list_del(&cpkt->list);
- rmnet_free_ctrl_pkt(cpkt);
- }
- atomic_set(&dev->notify_count, 0);
- spin_unlock_irqrestore(&dev->lock, flags);
-
+ frmnet_purge_responses(dev);
}
static int
@@ -876,11 +874,11 @@
status = usb_ep_queue(dev->notify, req, GFP_ATOMIC);
if (status) {
- atomic_dec(&dev->notify_count);
spin_lock_irqsave(&dev->lock, flags);
- cpkt = list_first_entry(&dev->cpkt_resp_q,
+ if (!list_empty(&dev->cpkt_resp_q)) {
+ atomic_dec(&dev->notify_count);
+ cpkt = list_first_entry(&dev->cpkt_resp_q,
struct rmnet_ctrl_pkt, list);
- if (cpkt) {
list_del(&cpkt->list);
rmnet_free_ctrl_pkt(cpkt);
}