| OLD | NEW |
| 1 /* qcusbnet.c - gobi network device | 1 /* qcusbnet.c - gobi network device |
| 2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. | 2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. |
| 3 | 3 |
| 4 * This program is free software; you can redistribute it and/or modify | 4 * This program is free software; you can redistribute it and/or modify |
| 5 * it under the terms of the GNU General Public License version 2 and | 5 * it under the terms of the GNU General Public License version 2 and |
| 6 * only version 2 as published by the Free Software Foundation. | 6 * only version 2 as published by the Free Software Foundation. |
| 7 | 7 |
| 8 * This program is distributed in the hope that it will be useful, | 8 * This program is distributed in the hope that it will be useful, |
| 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 if (entry == key) { | 61 if (entry == key) { |
| 62 kref_get(&entry->refcount); | 62 kref_get(&entry->refcount); |
| 63 mutex_unlock(&qcusbnet_lock); | 63 mutex_unlock(&qcusbnet_lock); |
| 64 return entry; | 64 return entry; |
| 65 } | 65 } |
| 66 } | 66 } |
| 67 mutex_unlock(&qcusbnet_lock); | 67 mutex_unlock(&qcusbnet_lock); |
| 68 return NULL; | 68 return NULL; |
| 69 } | 69 } |
| 70 | 70 |
| 71 static void wake_worker(struct worker *worker) |
| 72 { |
| 73 atomic_inc(&worker->work_count); |
| 74 wake_up(&worker->waitq); |
| 75 } |
| 76 |
| 71 int qc_suspend(struct usb_interface *iface, pm_message_t event) | 77 int qc_suspend(struct usb_interface *iface, pm_message_t event) |
| 72 { | 78 { |
| 73 struct usbnet *usbnet; | 79 struct usbnet *usbnet; |
| 74 struct qcusbnet *dev; | 80 struct qcusbnet *dev; |
| 75 | 81 |
| 76 if (!iface) | 82 if (!iface) |
| 77 return -ENOMEM; | 83 return -ENOMEM; |
| 78 | 84 |
| 79 usbnet = usb_get_intfdata(iface); | 85 usbnet = usb_get_intfdata(iface); |
| 80 | 86 |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 143 DBG("usbnet_resume error %d\n", ret); | 149 DBG("usbnet_resume error %d\n", ret); |
| 144 return ret; | 150 return ret; |
| 145 } | 151 } |
| 146 | 152 |
| 147 ret = qc_startread(dev); | 153 ret = qc_startread(dev); |
| 148 if (ret) { | 154 if (ret) { |
| 149 DBG("qc_startread error %d\n", ret); | 155 DBG("qc_startread error %d\n", ret); |
| 150 return ret; | 156 return ret; |
| 151 } | 157 } |
| 152 | 158 |
| 153 » » complete(&dev->worker.work); | 159 » » wake_worker(&dev->worker); |
| 154 } else { | 160 } else { |
| 155 DBG("nothing to resume\n"); | 161 DBG("nothing to resume\n"); |
| 156 return 0; | 162 return 0; |
| 157 } | 163 } |
| 158 | 164 |
| 159 return ret; | 165 return ret; |
| 160 } | 166 } |
| 161 | 167 |
| 162 static int qcnet_bind(struct usbnet *usbnet, struct usb_interface *iface) | 168 static int qcnet_bind(struct usbnet *usbnet, struct usb_interface *iface) |
| 163 { | 169 { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 } | 245 } |
| 240 | 246 |
| 241 if (urb->status) { | 247 if (urb->status) { |
| 242 DBG("urb finished with error %d\n", urb->status); | 248 DBG("urb finished with error %d\n", urb->status); |
| 243 } | 249 } |
| 244 | 250 |
| 245 spin_lock_irqsave(&worker->active_lock, flags); | 251 spin_lock_irqsave(&worker->active_lock, flags); |
| 246 worker->active = ERR_PTR(-EAGAIN); | 252 worker->active = ERR_PTR(-EAGAIN); |
| 247 spin_unlock_irqrestore(&worker->active_lock, flags); | 253 spin_unlock_irqrestore(&worker->active_lock, flags); |
| 248 /* XXX-fix race against qcnet_stop()? */ | 254 /* XXX-fix race against qcnet_stop()? */ |
| 249 » complete(&worker->work); | 255 » wake_worker(worker); |
| 250 usb_free_urb(urb); | 256 usb_free_urb(urb); |
| 251 } | 257 } |
| 252 | 258 |
| 253 static void qcnet_txtimeout(struct net_device *netdev) | 259 static void qcnet_txtimeout(struct net_device *netdev) |
| 254 { | 260 { |
| 255 struct list_head *node, *tmp; | 261 struct list_head *node, *tmp; |
| 256 struct qcusbnet *dev; | 262 struct qcusbnet *dev; |
| 257 struct worker *worker; | 263 struct worker *worker; |
| 258 struct urbreq *req; | 264 struct urbreq *req; |
| 259 unsigned long activeflags, listflags; | 265 unsigned long activeflags, listflags; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 280 | 286 |
| 281 spin_lock_irqsave(&worker->urbs_lock, listflags); | 287 spin_lock_irqsave(&worker->urbs_lock, listflags); |
| 282 list_for_each_safe(node, tmp, &worker->urbs) { | 288 list_for_each_safe(node, tmp, &worker->urbs) { |
| 283 req = list_entry(node, struct urbreq, node); | 289 req = list_entry(node, struct urbreq, node); |
| 284 usb_free_urb(req->urb); | 290 usb_free_urb(req->urb); |
| 285 list_del(&req->node); | 291 list_del(&req->node); |
| 286 kfree(req); | 292 kfree(req); |
| 287 } | 293 } |
| 288 spin_unlock_irqrestore(&worker->urbs_lock, listflags); | 294 spin_unlock_irqrestore(&worker->urbs_lock, listflags); |
| 289 | 295 |
| 290 » complete(&worker->work); | 296 » wake_worker(worker); |
| 297 } |
| 298 |
| 299 static int worker_should_wake(struct worker *worker) |
| 300 { |
| 301 » if (kthread_should_stop()) |
| 302 » » return 1; |
| 303 » /* This is safe only because we are the only place that decrements this |
| 304 » * counter. */ |
| 305 » if (atomic_read(&worker->work_count)) |
| 306 » » return 1; |
| 307 » return 0; |
| 291 } | 308 } |
| 292 | 309 |
| 293 static int qcnet_worker(void *arg) | 310 static int qcnet_worker(void *arg) |
| 294 { | 311 { |
| 295 struct list_head *node, *tmp; | 312 struct list_head *node, *tmp; |
| 296 unsigned long activeflags, listflags; | 313 unsigned long activeflags, listflags; |
| 297 struct urbreq *req; | 314 struct urbreq *req; |
| 298 int status; | 315 int status; |
| 299 struct usb_device *usbdev; | 316 struct usb_device *usbdev; |
| 300 struct worker *worker = arg; | 317 struct worker *worker = arg; |
| 301 if (!worker) { | 318 if (!worker) { |
| 302 DBG("passed null pointer\n"); | 319 DBG("passed null pointer\n"); |
| 303 return -EINVAL; | 320 return -EINVAL; |
| 304 } | 321 } |
| 305 | 322 |
| 306 usbdev = interface_to_usbdev(worker->iface); | 323 usbdev = interface_to_usbdev(worker->iface); |
| 307 | 324 |
| 308 DBG("traffic thread started\n"); | 325 DBG("traffic thread started\n"); |
| 309 | 326 |
| 310 » while (!worker->exit && !kthread_should_stop()) { | 327 » while (!kthread_should_stop()) { |
| 311 » » wait_for_completion_interruptible(&worker->work); | 328 » » wait_event(worker->waitq, worker_should_wake(worker)); |
| 312 | 329 |
| 313 » » if (worker->exit || kthread_should_stop()) { | 330 » » if (kthread_should_stop()) |
| 314 » » » spin_lock_irqsave(&worker->active_lock, activeflags); | |
| 315 » » » if (worker->active) { | |
| 316 » » » » usb_kill_urb(worker->active); | |
| 317 » » » } | |
| 318 » » » spin_unlock_irqrestore(&worker->active_lock, activeflags
); | |
| 319 | |
| 320 » » » spin_lock_irqsave(&worker->urbs_lock, listflags); | |
| 321 » » » list_for_each_safe(node, tmp, &worker->urbs) { | |
| 322 » » » » req = list_entry(node, struct urbreq, node); | |
| 323 » » » » usb_free_urb(req->urb); | |
| 324 » » » » list_del(&req->node); | |
| 325 » » » » kfree(req); | |
| 326 » » » } | |
| 327 » » » spin_unlock_irqrestore(&worker->urbs_lock, listflags); | |
| 328 | |
| 329 break; | 331 break; |
| 330 » » } | 332 » » atomic_dec(&worker->work_count); |
| 331 | 333 |
| 332 spin_lock_irqsave(&worker->active_lock, activeflags); | 334 spin_lock_irqsave(&worker->active_lock, activeflags); |
| 333 if (IS_ERR(worker->active) && PTR_ERR(worker->active) == -EAGAIN
) { | 335 if (IS_ERR(worker->active) && PTR_ERR(worker->active) == -EAGAIN
) { |
| 334 worker->active = NULL; | 336 worker->active = NULL; |
| 335 spin_unlock_irqrestore(&worker->active_lock, activeflags
); | 337 spin_unlock_irqrestore(&worker->active_lock, activeflags
); |
| 336 usb_autopm_put_interface(worker->iface); | 338 usb_autopm_put_interface(worker->iface); |
| 337 spin_lock_irqsave(&worker->active_lock, activeflags); | 339 spin_lock_irqsave(&worker->active_lock, activeflags); |
| 338 } | 340 } |
| 339 | 341 |
| 340 if (worker->active) { | 342 if (worker->active) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 } | 377 } |
| 376 | 378 |
| 377 status = usb_submit_urb(worker->active, GFP_KERNEL); | 379 status = usb_submit_urb(worker->active, GFP_KERNEL); |
| 378 if (status < 0) { | 380 if (status < 0) { |
| 379 DBG("Failed to submit URB: %d. Packet dropped\n", statu
s); | 381 DBG("Failed to submit URB: %d. Packet dropped\n", statu
s); |
| 380 spin_lock_irqsave(&worker->active_lock, activeflags); | 382 spin_lock_irqsave(&worker->active_lock, activeflags); |
| 381 usb_free_urb(worker->active); | 383 usb_free_urb(worker->active); |
| 382 worker->active = NULL; | 384 worker->active = NULL; |
| 383 spin_unlock_irqrestore(&worker->active_lock, activeflags
); | 385 spin_unlock_irqrestore(&worker->active_lock, activeflags
); |
| 384 usb_autopm_put_interface(worker->iface); | 386 usb_autopm_put_interface(worker->iface); |
| 385 » » » complete(&worker->work); | 387 » » » wake_worker(worker); |
| 386 } | 388 } |
| 387 | 389 |
| 388 kfree(req); | 390 kfree(req); |
| 389 } | 391 } |
| 390 | 392 |
| 393 spin_lock_irqsave(&worker->active_lock, activeflags); |
| 394 if (worker->active) { |
| 395 usb_kill_urb(worker->active); |
| 396 } |
| 397 spin_unlock_irqrestore(&worker->active_lock, activeflags); |
| 398 |
| 399 spin_lock_irqsave(&worker->urbs_lock, listflags); |
| 400 list_for_each_safe(node, tmp, &worker->urbs) { |
| 401 req = list_entry(node, struct urbreq, node); |
| 402 usb_free_urb(req->urb); |
| 403 list_del(&req->node); |
| 404 kfree(req); |
| 405 } |
| 406 spin_unlock_irqrestore(&worker->urbs_lock, listflags); |
| 407 |
| 391 DBG("traffic thread exiting\n"); | 408 DBG("traffic thread exiting\n"); |
| 392 worker->thread = NULL; | 409 worker->thread = NULL; |
| 393 return 0; | 410 return 0; |
| 394 } | 411 } |
| 395 | 412 |
| 396 static int qcnet_startxmit(struct sk_buff *skb, struct net_device *netdev) | 413 static int qcnet_startxmit(struct sk_buff *skb, struct net_device *netdev) |
| 397 { | 414 { |
| 398 unsigned long listflags; | 415 unsigned long listflags; |
| 399 struct qcusbnet *dev; | 416 struct qcusbnet *dev; |
| 400 struct worker *worker; | 417 struct worker *worker; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 } | 462 } |
| 446 memcpy(data, skb->data, skb->len); | 463 memcpy(data, skb->data, skb->len); |
| 447 | 464 |
| 448 usb_fill_bulk_urb(req->urb, dev->usbnet->udev, dev->usbnet->out, | 465 usb_fill_bulk_urb(req->urb, dev->usbnet->udev, dev->usbnet->out, |
| 449 data, skb->len, qcnet_urbhook, worker); | 466 data, skb->len, qcnet_urbhook, worker); |
| 450 | 467 |
| 451 spin_lock_irqsave(&worker->urbs_lock, listflags); | 468 spin_lock_irqsave(&worker->urbs_lock, listflags); |
| 452 list_add_tail(&req->node, &worker->urbs); | 469 list_add_tail(&req->node, &worker->urbs); |
| 453 spin_unlock_irqrestore(&worker->urbs_lock, listflags); | 470 spin_unlock_irqrestore(&worker->urbs_lock, listflags); |
| 454 | 471 |
| 455 » complete(&worker->work); | 472 » wake_worker(worker); |
| 456 | 473 |
| 457 netdev->trans_start = jiffies; | 474 netdev->trans_start = jiffies; |
| 458 dev_kfree_skb_any(skb); | 475 dev_kfree_skb_any(skb); |
| 459 | 476 |
| 460 return NETDEV_TX_OK; | 477 return NETDEV_TX_OK; |
| 461 } | 478 } |
| 462 | 479 |
| 463 static int qcnet_open(struct net_device *netdev) | 480 static int qcnet_open(struct net_device *netdev) |
| 464 { | 481 { |
| 465 int status = 0; | 482 int status = 0; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 477 return -ENXIO; | 494 return -ENXIO; |
| 478 } | 495 } |
| 479 | 496 |
| 480 DBG("\n"); | 497 DBG("\n"); |
| 481 | 498 |
| 482 dev->worker.iface = dev->iface; | 499 dev->worker.iface = dev->iface; |
| 483 INIT_LIST_HEAD(&dev->worker.urbs); | 500 INIT_LIST_HEAD(&dev->worker.urbs); |
| 484 dev->worker.active = NULL; | 501 dev->worker.active = NULL; |
| 485 spin_lock_init(&dev->worker.urbs_lock); | 502 spin_lock_init(&dev->worker.urbs_lock); |
| 486 spin_lock_init(&dev->worker.active_lock); | 503 spin_lock_init(&dev->worker.active_lock); |
| 487 » init_completion(&dev->worker.work); | 504 » atomic_set(&dev->worker.work_count, 0); |
| 505 » init_waitqueue_head(&dev->worker.waitq); |
| 488 | 506 |
| 489 dev->worker.exit = 0; | |
| 490 dev->worker.thread = kthread_run(qcnet_worker, &dev->worker, "qcnet_work
er"); | 507 dev->worker.thread = kthread_run(qcnet_worker, &dev->worker, "qcnet_work
er"); |
| 491 if (IS_ERR(dev->worker.thread)) { | 508 if (IS_ERR(dev->worker.thread)) { |
| 492 DBG("AutoPM thread creation error\n"); | 509 DBG("AutoPM thread creation error\n"); |
| 493 return PTR_ERR(dev->worker.thread); | 510 return PTR_ERR(dev->worker.thread); |
| 494 } | 511 } |
| 495 | 512 |
| 496 qc_cleardown(dev, DOWN_NET_IFACE_STOPPED); | 513 qc_cleardown(dev, DOWN_NET_IFACE_STOPPED); |
| 497 if (dev->open) { | 514 if (dev->open) { |
| 498 status = dev->open(netdev); | 515 status = dev->open(netdev); |
| 499 if (status == 0) { | 516 if (status == 0) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 516 return -ENXIO; | 533 return -ENXIO; |
| 517 } | 534 } |
| 518 | 535 |
| 519 dev = (struct qcusbnet *)usbnet->data[0]; | 536 dev = (struct qcusbnet *)usbnet->data[0]; |
| 520 if (!dev) { | 537 if (!dev) { |
| 521 DBG("failed to get QMIDevice\n"); | 538 DBG("failed to get QMIDevice\n"); |
| 522 return -ENXIO; | 539 return -ENXIO; |
| 523 } | 540 } |
| 524 | 541 |
| 525 qc_setdown(dev, DOWN_NET_IFACE_STOPPED); | 542 qc_setdown(dev, DOWN_NET_IFACE_STOPPED); |
| 526 dev->worker.exit = 1; | |
| 527 complete(&dev->worker.work); | |
| 528 kthread_stop(dev->worker.thread); | 543 kthread_stop(dev->worker.thread); |
| 529 DBG("thread stopped\n"); | 544 DBG("thread stopped\n"); |
| 530 | 545 |
| 531 if (dev->stop != NULL) | 546 if (dev->stop != NULL) |
| 532 return dev->stop(netdev); | 547 return dev->stop(netdev); |
| 533 return 0; | 548 return 0; |
| 534 } | 549 } |
| 535 | 550 |
| 536 static const struct driver_info qc_netinfo = { | 551 static const struct driver_info qc_netinfo = { |
| 537 .description = "QCUSBNet Ethernet Device", | 552 .description = "QCUSBNet Ethernet Device", |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 646 memset(&(dev->meid), '0', 14); | 661 memset(&(dev->meid), '0', 14); |
| 647 | 662 |
| 648 dev->valid = false; | 663 dev->valid = false; |
| 649 memset(&dev->qmi, 0, sizeof(dev->qmi)); | 664 memset(&dev->qmi, 0, sizeof(dev->qmi)); |
| 650 | 665 |
| 651 dev->qmi.devclass = devclass; | 666 dev->qmi.devclass = devclass; |
| 652 | 667 |
| 653 kref_init(&dev->refcount); | 668 kref_init(&dev->refcount); |
| 654 INIT_LIST_HEAD(&dev->node); | 669 INIT_LIST_HEAD(&dev->node); |
| 655 INIT_LIST_HEAD(&dev->qmi.clients); | 670 INIT_LIST_HEAD(&dev->qmi.clients); |
| 656 » init_completion(&dev->worker.work); | 671 » atomic_set(&dev->worker.work_count, 0); |
| 672 » init_waitqueue_head(&dev->worker.waitq); |
| 657 spin_lock_init(&dev->qmi.clients_lock); | 673 spin_lock_init(&dev->qmi.clients_lock); |
| 658 | 674 |
| 659 dev->down = 0; | 675 dev->down = 0; |
| 660 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION); | 676 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION); |
| 661 qc_setdown(dev, DOWN_NET_IFACE_STOPPED); | 677 qc_setdown(dev, DOWN_NET_IFACE_STOPPED); |
| 662 | 678 |
| 663 status = qc_register(dev); | 679 status = qc_register(dev); |
| 664 if (status) { | 680 if (status) { |
| 665 qc_deregister(dev); | 681 qc_deregister(dev); |
| 666 } else { | 682 } else { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 } | 726 } |
| 711 module_exit(modexit); | 727 module_exit(modexit); |
| 712 | 728 |
| 713 MODULE_VERSION(DRIVER_VERSION); | 729 MODULE_VERSION(DRIVER_VERSION); |
| 714 MODULE_AUTHOR(DRIVER_AUTHOR); | 730 MODULE_AUTHOR(DRIVER_AUTHOR); |
| 715 MODULE_DESCRIPTION(DRIVER_DESC); | 731 MODULE_DESCRIPTION(DRIVER_DESC); |
| 716 MODULE_LICENSE("Dual BSD/GPL"); | 732 MODULE_LICENSE("Dual BSD/GPL"); |
| 717 | 733 |
| 718 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR); | 734 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR); |
| 719 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not"); | 735 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not"); |
| OLD | NEW |