ChangeSet 1.987, 2003/02/04 11:46:01+11:00, [EMAIL PROTECTED]
[PATCH] USB speedtouch: let the tasklet do all processing of speedtouch receive urbs
speedtouch: move all processing of receive urbs to udsl_atm_processqueue. This has
several advantages, as will be seen in the next few patches. The most important is
that it makes it easy to reuse of the urb's buffer (right now a new buffer is
allocated every time the urb completes). By the way, this patch is much smaller than
it looks: most of the bulk is due to indentation changes.
diff -Nru a/drivers/usb/misc/speedtouch.c b/drivers/usb/misc/speedtouch.c
--- a/drivers/usb/misc/speedtouch.c Tue Feb 4 15:16:30 2003
+++ b/drivers/usb/misc/speedtouch.c Tue Feb 4 15:16:30 2003
@@ -58,7 +58,6 @@
#include <linux/usb.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
-
#include <linux/atm.h>
#include <linux/atmdev.h>
#include "atmsar.h"
@@ -120,6 +119,7 @@
/* context declarations */
struct udsl_data_ctx {
+ struct list_head list;
struct sk_buff *skb;
struct urb *urb;
struct udsl_instance_data *instance;
@@ -137,8 +137,6 @@
*/
struct udsl_instance_data {
- struct tasklet_struct recvqueue_tasklet;
-
/* usb device part */
struct usb_device *usb_dev;
struct udsl_data_ctx rcvbufs [UDSL_NUMBER_RCV_URBS];
@@ -148,9 +146,14 @@
/* atm device part */
struct atm_dev *atm_dev;
- struct sk_buff_head recvqueue;
struct atmsar_vcc_data *atmsar_vcc_list;
+
+ /* receiving */
+ spinlock_t completed_receivers_lock;
+ struct list_head completed_receivers;
+
+ struct tasklet_struct recvqueue_tasklet;
};
static const char udsl_driver_name [] = "Alcatel SpeedTouch USB";
@@ -194,6 +197,7 @@
struct sk_buff *skb);
static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void
*user_data);
static int udsl_usb_cancelsends (struct udsl_instance_data *instance, struct atm_vcc
*vcc);
+static void udsl_usb_data_receive (struct urb *urb, struct pt_regs *regs);
static struct usb_driver udsl_usb_driver = {
.name = udsl_driver_name,
@@ -217,7 +221,6 @@
static void udsl_atm_stopdevice (struct udsl_instance_data *instance)
{
struct atm_vcc *walk;
- struct sk_buff *skb;
struct atm_dev *atm_dev;
if (!instance->atm_dev)
@@ -225,10 +228,6 @@
atm_dev = instance->atm_dev;
- /* clean queue */
- while ((skb = skb_dequeue (&instance->recvqueue)))
- dev_kfree_skb (skb);
-
atm_dev->signal = ATM_PHY_SIG_LOST;
walk = atm_dev->vccs;
shutdown_atm_dev (atm_dev);
@@ -347,54 +346,92 @@
static void udsl_atm_processqueue (unsigned long data)
{
struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
+ struct udsl_data_ctx *ctx;
+ unsigned long flags;
+ struct urb *urb;
struct atmsar_vcc_data *atmsar_vcc = NULL;
struct sk_buff *new = NULL, *skb = NULL, *tmp = NULL;
PDEBUG ("udsl_atm_processqueue entered\n");
- while ((skb = skb_dequeue (&instance->recvqueue))) {
- PDEBUG ("skb = %p, skb->len = %d\n", skb, skb->len);
- PACKETDEBUG (skb->data, skb->len);
-
- while ((new =
- atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
- &atmsar_vcc)) != NULL) {
- PDEBUG ("(after cell processing)skb->len = %d\n", new->len);
- switch (atmsar_vcc->type) {
- case ATMSAR_TYPE_AAL5:
- tmp = new;
- new = atmsar_decode_aal5 (atmsar_vcc, new);
-
- /* we can't send NULL skbs upstream, the ATM layer
would try to close the vcc... */
- if (new) {
- PDEBUG ("(after aal5 decap) skb->len = %d\n",
new->len);
- if (new->len && atm_charge (atmsar_vcc->vcc,
new->truesize)) {
- PACKETDEBUG (new->data, new->len);
- atmsar_vcc->vcc->push
(atmsar_vcc->vcc, new);
+ spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+ while (!list_empty (&instance->completed_receivers)) {
+ ctx = list_entry (instance->completed_receivers.next, struct
+udsl_data_ctx, list);
+ list_del (&ctx->list);
+ spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+
+ urb = ctx->urb;
+ PDEBUG ("udsl_atm_processqueue: got packet %p with length %d and
+status %d\n", urb, urb->actual_length, urb->status);
+
+ switch (urb->status) {
+ case 0:
+ PDEBUG ("udsl_atm_processqueue: processing urb with ctx %p,
+urb %p, skb %p\n", ctx, urb, ctx->skb);
+
+ /* update the skb structure */
+ skb = ctx->skb;
+ skb_put (skb, urb->actual_length);
+
+ /* get a new skb */
+ ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE);
+ if (!ctx->skb)
+ PDEBUG ("No skb, loosing urb.\n");
+ else {
+ usb_fill_bulk_urb (urb,
+ instance->usb_dev,
+ usb_rcvbulkpipe (instance->usb_dev,
+UDSL_ENDPOINT_DATA_IN),
+ (unsigned char *) ctx->skb->data,
+ UDSL_RECEIVE_BUFFER_SIZE,
+udsl_usb_data_receive, ctx);
+ usb_submit_urb (urb, GFP_ATOMIC);
+ }
+
+ PDEBUG ("skb = %p, skb->len = %d\n", skb, skb->len);
+ PACKETDEBUG (skb->data, skb->len);
+
+ while ((new =
+ atmsar_decode_rawcell (instance->atmsar_vcc_list, skb,
+ &atmsar_vcc)) != NULL) {
+ PDEBUG ("(after cell processing)skb->len = %d\n",
+new->len);
+
+ switch (atmsar_vcc->type) {
+ case ATMSAR_TYPE_AAL5:
+ tmp = new;
+ new = atmsar_decode_aal5 (atmsar_vcc, new);
+
+ /* we can't send NULL skbs upstream, the ATM
+layer would try to close the vcc... */
+ if (new) {
+ PDEBUG ("(after aal5 decap) skb->len =
+%d\n", new->len);
+ if (new->len && atm_charge
+(atmsar_vcc->vcc, new->truesize)) {
+ PACKETDEBUG (new->data,
+new->len);
+ atmsar_vcc->vcc->push
+(atmsar_vcc->vcc, new);
+ } else {
+ PDEBUG
+ ("dropping incoming packet
+: rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d\n",
+ atomic_read
+(&atmsar_vcc->vcc->rx_inuse),
+
+atmsar_vcc->vcc->sk->rcvbuf, new->truesize);
+ dev_kfree_skb (new);
+ }
} else {
- PDEBUG
- ("dropping incoming packet :
rx_inuse = %d, vcc->sk->rcvbuf = %d, skb->true_size = %d\n",
- atomic_read
(&atmsar_vcc->vcc->rx_inuse),
- atmsar_vcc->vcc->sk->rcvbuf,
new->truesize);
- dev_kfree_skb (new);
+ PDEBUG ("atmsar_decode_aal5 returned
+NULL!\n");
+ dev_kfree_skb (tmp);
}
- } else {
- PDEBUG ("atmsar_decode_aal5 returned NULL!\n");
- dev_kfree_skb (tmp);
+ break;
+ default:
+ /* not supported. we delete the skb. */
+ printk (KERN_INFO
+ "SpeedTouch USB: illegal vcc type.
+Dropping packet.\n");
+ dev_kfree_skb (new);
+ break;
}
- break;
- default:
- /* not supported. we delete the skb. */
- printk (KERN_INFO
- "SpeedTouch USB: illegal vcc type. Dropping
packet.\n");
- dev_kfree_skb (new);
- break;
}
- };
- dev_kfree_skb (skb);
- };
+ dev_kfree_skb (skb);
+ default:
+ break;
+ }
- PDEBUG ("udsl_atm_processqueue successfull\n");
+ spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+ }
+ spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+ PDEBUG ("udsl_atm_processqueue successful\n");
}
@@ -617,57 +654,24 @@
/********* receive *******/
static void udsl_usb_data_receive (struct urb *urb, struct pt_regs *regs)
{
- struct udsl_data_ctx *ctx;
struct udsl_instance_data *instance;
+ struct udsl_data_ctx *ctx;
+ unsigned long flags;
- if (!urb)
- return;
-
- PDEBUG ("udsl_usb_receive_data entered, got packet %p with length %d an status
%d\n", urb,
- urb->actual_length, urb->status);
-
- ctx = urb->context;
- if (!ctx || !ctx->skb)
- return;
-
- instance = ctx->instance;
+ PDEBUG ("udsl_usb_data_receive entered\n");
- switch (urb->status) {
- case 0:
- PDEBUG ("udsl_usb_data_receive: processing urb with ctx %p, urb %p
(%p), skb %p\n",
- ctx, ctx ? ctx->urb : NULL, urb, ctx ? ctx->skb : NULL);
- /* update the skb structure */
- skb_put (ctx->skb, urb->actual_length);
-
- /* queue the skb for processing and wake the SAR */
- skb_queue_tail (&instance->recvqueue, ctx->skb);
- tasklet_schedule (&instance->recvqueue_tasklet);
- /* get a new skb */
- ctx->skb = dev_alloc_skb (UDSL_RECEIVE_BUFFER_SIZE);
- if (!ctx->skb) {
- PDEBUG ("No skb, loosing urb.\n");
- usb_free_urb (ctx->urb);
- ctx->urb = NULL;
- return;
- }
- break;
- case -ENOENT: /* buffer was unlinked */
- case -EILSEQ: /* unplug or timeout */
- case -ETIMEDOUT: /* unplug or timeout */
- /*
- * we don't do anything here and we don't resubmit
- */
+ if (!urb || !(ctx = urb->context) || !(instance = ctx->instance)) {
+ PDEBUG ("udsl_usb_data_receive: bad urb!\n");
return;
}
- usb_fill_bulk_urb (urb,
- instance->usb_dev,
- usb_rcvbulkpipe (instance->usb_dev, UDSL_ENDPOINT_DATA_IN),
- (unsigned char *) ctx->skb->data,
- UDSL_RECEIVE_BUFFER_SIZE, udsl_usb_data_receive, ctx);
- usb_submit_urb (urb, GFP_ATOMIC);
- return;
-};
+ /* may not be in_interrupt() */
+ spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+ list_add_tail (&ctx->list, &instance->completed_receivers);
+ spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+ PDEBUG ("udsl_complete_receive: scheduling tasklet\n");
+ tasklet_schedule (&instance->recvqueue_tasklet);
+}
static int udsl_usb_data_init (struct udsl_instance_data *instance)
{
@@ -727,16 +731,14 @@
if (!instance->data_started)
return 0;
- /* destroy urbs */
- for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
- struct udsl_data_ctx *ctx = &(instance->rcvbufs[i]);
+ tasklet_disable (&instance->recvqueue_tasklet);
- if ((!ctx->urb) || (!ctx->skb))
- continue;
+ for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++)
+ usb_unlink_urb (instance->rcvbufs[i].urb);
- usb_unlink_urb (ctx->urb);
- }
+ INIT_LIST_HEAD (&instance->completed_receivers);
+ tasklet_enable (&instance->recvqueue_tasklet);
tasklet_kill (&instance->recvqueue_tasklet);
for (i = 0; i < UDSL_NUMBER_SND_URBS; i++) {
@@ -816,7 +818,8 @@
instance->usb_dev = dev;
- skb_queue_head_init (&instance->recvqueue);
+ spin_lock_init (&instance->completed_receivers_lock);
+ INIT_LIST_HEAD (&instance->completed_receivers);
tasklet_init (&instance->recvqueue_tasklet, udsl_atm_processqueue, (unsigned
long) instance);
-------------------------------------------------------
This SF.NET email is sponsored by:
SourceForge Enterprise Edition + IBM + LinuxWorld = Something 2 See!
http://www.vasoftware.com
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel