Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Unified Diff: drivers/net/usb/gobi/qcusbnet.c

Issue 6913008: CHROMIUM: gobi: Remove worker.exit hack. (Closed) Base URL: ssh://gitrw.chromium.org:9222/kernel.git@0.12.433.B
Patch Set: Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | drivers/net/usb/gobi/structs.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: drivers/net/usb/gobi/qcusbnet.c
diff --git a/drivers/net/usb/gobi/qcusbnet.c b/drivers/net/usb/gobi/qcusbnet.c
index 146a3eb55079edba512bd906afc8370a0f27b4ff..871a7e2a5a65995ba90476d478a39f0cda130c26 100644
--- a/drivers/net/usb/gobi/qcusbnet.c
+++ b/drivers/net/usb/gobi/qcusbnet.c
@@ -68,6 +68,12 @@ struct qcusbnet *qcusbnet_get(struct qcusbnet *key)
return NULL;
}
+static void wake_worker(struct worker *worker)
+{
+ atomic_inc(&worker->work_count);
+ wake_up(&worker->waitq);
+}
+
int qc_suspend(struct usb_interface *iface, pm_message_t event)
{
struct usbnet *usbnet;
@@ -150,7 +156,7 @@ static int qc_resume(struct usb_interface *iface)
return ret;
}
- complete(&dev->worker.work);
+ wake_worker(&dev->worker);
} else {
DBG("nothing to resume\n");
return 0;
@@ -246,7 +252,7 @@ static void qcnet_urbhook(struct urb *urb)
worker->active = ERR_PTR(-EAGAIN);
spin_unlock_irqrestore(&worker->active_lock, flags);
/* XXX-fix race against qcnet_stop()? */
- complete(&worker->work);
+ wake_worker(worker);
usb_free_urb(urb);
}
@@ -287,7 +293,18 @@ static void qcnet_txtimeout(struct net_device *netdev)
}
spin_unlock_irqrestore(&worker->urbs_lock, listflags);
- complete(&worker->work);
+ wake_worker(worker);
+}
+
+static int worker_should_wake(struct worker *worker)
+{
+ if (kthread_should_stop())
+ return 1;
+ /* This is safe only because we are the only place that decrements this
+ * counter. */
+ if (atomic_read(&worker->work_count))
+ return 1;
+ return 0;
}
static int qcnet_worker(void *arg)
@@ -307,27 +324,12 @@ static int qcnet_worker(void *arg)
DBG("traffic thread started\n");
- while (!worker->exit && !kthread_should_stop()) {
- wait_for_completion_interruptible(&worker->work);
-
- if (worker->exit || kthread_should_stop()) {
- spin_lock_irqsave(&worker->active_lock, activeflags);
- if (worker->active) {
- usb_kill_urb(worker->active);
- }
- spin_unlock_irqrestore(&worker->active_lock, activeflags);
-
- spin_lock_irqsave(&worker->urbs_lock, listflags);
- list_for_each_safe(node, tmp, &worker->urbs) {
- req = list_entry(node, struct urbreq, node);
- usb_free_urb(req->urb);
- list_del(&req->node);
- kfree(req);
- }
- spin_unlock_irqrestore(&worker->urbs_lock, listflags);
+ while (!kthread_should_stop()) {
+ wait_event(worker->waitq, worker_should_wake(worker));
+ if (kthread_should_stop())
break;
- }
+ atomic_dec(&worker->work_count);
spin_lock_irqsave(&worker->active_lock, activeflags);
if (IS_ERR(worker->active) && PTR_ERR(worker->active) == -EAGAIN) {
@@ -382,12 +384,27 @@ static int qcnet_worker(void *arg)
worker->active = NULL;
spin_unlock_irqrestore(&worker->active_lock, activeflags);
usb_autopm_put_interface(worker->iface);
- complete(&worker->work);
+ wake_worker(worker);
}
kfree(req);
}
+ spin_lock_irqsave(&worker->active_lock, activeflags);
+ if (worker->active) {
+ usb_kill_urb(worker->active);
+ }
+ spin_unlock_irqrestore(&worker->active_lock, activeflags);
+
+ spin_lock_irqsave(&worker->urbs_lock, listflags);
+ list_for_each_safe(node, tmp, &worker->urbs) {
+ req = list_entry(node, struct urbreq, node);
+ usb_free_urb(req->urb);
+ list_del(&req->node);
+ kfree(req);
+ }
+ spin_unlock_irqrestore(&worker->urbs_lock, listflags);
+
DBG("traffic thread exiting\n");
worker->thread = NULL;
return 0;
@@ -452,7 +469,7 @@ static int qcnet_startxmit(struct sk_buff *skb, struct net_device *netdev)
list_add_tail(&req->node, &worker->urbs);
spin_unlock_irqrestore(&worker->urbs_lock, listflags);
- complete(&worker->work);
+ wake_worker(worker);
netdev->trans_start = jiffies;
dev_kfree_skb_any(skb);
@@ -484,9 +501,9 @@ static int qcnet_open(struct net_device *netdev)
dev->worker.active = NULL;
spin_lock_init(&dev->worker.urbs_lock);
spin_lock_init(&dev->worker.active_lock);
- init_completion(&dev->worker.work);
+ atomic_set(&dev->worker.work_count, 0);
+ init_waitqueue_head(&dev->worker.waitq);
- dev->worker.exit = 0;
dev->worker.thread = kthread_run(qcnet_worker, &dev->worker, "qcnet_worker");
if (IS_ERR(dev->worker.thread)) {
DBG("AutoPM thread creation error\n");
@@ -523,8 +540,6 @@ int qcnet_stop(struct net_device *netdev)
}
qc_setdown(dev, DOWN_NET_IFACE_STOPPED);
- dev->worker.exit = 1;
- complete(&dev->worker.work);
kthread_stop(dev->worker.thread);
DBG("thread stopped\n");
@@ -653,7 +668,8 @@ int qcnet_probe(struct usb_interface *iface, const struct usb_device_id *vidpids
kref_init(&dev->refcount);
INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->qmi.clients);
- init_completion(&dev->worker.work);
+ atomic_set(&dev->worker.work_count, 0);
+ init_waitqueue_head(&dev->worker.waitq);
spin_lock_init(&dev->qmi.clients_lock);
dev->down = 0;
« no previous file with comments | « no previous file | drivers/net/usb/gobi/structs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698