ChangeSet 1.1224, 2003/06/18 16:35:11-07:00, [EMAIL PROTECTED]

[PATCH] USB speedtouch: receive code rewrite

Main points:
- receive buffers are decoupled from urbs, so an urb can be
resubmitted with a new buffer before the old buffer is processed.
- the packet reconstruction code is much simpler.
- locking is simplified by the fact that only the tasklet launches
receive urbs


 drivers/usb/speedtouch.c |  466 +++++++++++++++++++----------------------------
 1 files changed, 191 insertions(+), 275 deletions(-)


diff -Nru a/drivers/usb/speedtouch.c b/drivers/usb/speedtouch.c
--- a/drivers/usb/speedtouch.c  Wed Jun 18 17:35:55 2003
+++ b/drivers/usb/speedtouch.c  Wed Jun 18 17:35:55 2003
@@ -104,8 +104,9 @@
 
 #define UDSL_NUM_RCV_URBS              1
 #define UDSL_NUM_SND_URBS              1
+#define UDSL_NUM_RCV_BUFS              (2*UDSL_NUM_RCV_URBS)
 #define UDSL_NUM_SND_BUFS              (2*UDSL_NUM_SND_URBS)
-#define UDSL_RCV_BUF_SIZE              64 /* ATM cells */
+#define UDSL_RCV_BUF_SIZE              32 /* ATM cells */
 #define UDSL_SND_BUF_SIZE              64 /* ATM cells */
 
 #define UDSL_IOCTL_LINE_UP             1
@@ -128,9 +129,15 @@
 
 /* receive */
 
+struct udsl_receive_buffer {
+       struct list_head list;
+       unsigned char *base;
+       unsigned int filled_cells;
+};
+
 struct udsl_receiver {
        struct list_head list;
-       struct sk_buff *skb;
+       struct udsl_receive_buffer *buffer;
        struct urb *urb;
        struct udsl_instance_data *instance;
 };
@@ -190,14 +197,14 @@
 
        /* receive */
        struct udsl_receiver receivers [UDSL_NUM_RCV_URBS];
+       struct udsl_receive_buffer receive_buffers [UDSL_NUM_RCV_BUFS];
 
-       spinlock_t spare_receivers_lock;
+       spinlock_t receive_lock;
        struct list_head spare_receivers;
-
-       spinlock_t completed_receivers_lock;
-       struct list_head completed_receivers;
+       struct list_head filled_receive_buffers;
 
        struct tasklet_struct receive_tasklet;
+       struct list_head spare_receive_buffers;
 
        /* send */
        struct udsl_sender senders [UDSL_NUM_SND_URBS];
@@ -262,133 +269,110 @@
        return NULL;
 }
 
-static struct sk_buff *udsl_decode_rawcell (struct udsl_instance_data *instance, 
struct sk_buff *skb, struct udsl_vcc_data **ctx)
+static void udsl_extract_cells (struct udsl_instance_data *instance, unsigned char 
*source, unsigned int howmany)
 {
-       if (!instance || !skb || !ctx)
-               return NULL;
-       if (!skb->data || !skb->tail)
-               return NULL;
+       struct udsl_vcc_data *cached_vcc = NULL;
+       struct atm_vcc *vcc;
+       struct sk_buff *skb;
+       struct udsl_vcc_data *vcc_data;
+       int cached_vci = 0;
+       unsigned int i;
+       unsigned int length;
+       unsigned int pdu_length;
+       int pti;
+       int vci;
+       short cached_vpi = 0;
+       short vpi;
 
-       while (skb->len) {
-               unsigned char *cell = skb->data;
-               unsigned char *cell_payload;
-               struct udsl_vcc_data *vcc;
-               short vpi;
-               int vci;
-
-               vpi = ((cell [0] & 0x0f) << 4) | (cell [1] >> 4);
-               vci = ((cell [1] & 0x0f) << 12) | (cell [2] << 4) | (cell [3] >> 4);
-
-               vdbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", instance, skb, 
ctx);
-               vdbg ("udsl_decode_rawcell skb->data %p, skb->tail %p", skb->data, 
skb->tail);
-
-               /* here should the header CRC check be... */
-
-               if (!(vcc = udsl_find_vcc (instance, vpi, vci))) {
-                       dbg ("udsl_decode_rawcell: no vcc found for packet on vpi %d, 
vci %d", vpi, vci);
-                       __skb_pull (skb, min (skb->len, (unsigned) 53));
+       for (i = 0; i < howmany; i++, source += ATM_CELL_SIZE) {
+               vpi = ((source [0] & 0x0f) << 4) | (source [1] >> 4);
+               vci = ((source [1] & 0x0f) << 12) | (source [2] << 4) | (source [3] >> 
4);
+               pti = (source [3] & 0x2) != 0;
+
+               vdbg ("udsl_extract_cells: vpi %hd, vci %d, pti %d", vpi, vci, pti);
+
+               if (cached_vcc && (vci == cached_vci) && (vpi == cached_vpi))
+                       vcc_data = cached_vcc;
+               else if ((vcc_data = udsl_find_vcc (instance, vpi, vci))) {
+                       cached_vcc = vcc_data;
+                       cached_vpi = vpi;
+                       cached_vci = vci;
                } else {
-                       vdbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, 
vci %d", vcc, vpi, vci);
+                       dbg ("udsl_extract_cells: unknown vpi/vci (%hd/%d)!", vpi, 
vci);
+                       continue;
+               }
 
-                       if (skb->len >= 53) {
-                               cell_payload = cell + 5;
+               vcc = vcc_data->vcc;
 
-                               if (!vcc->skb)
-                                       vcc->skb = dev_alloc_skb (vcc->max_pdu);
+               if (!vcc_data->skb && !(vcc_data->skb = dev_alloc_skb 
(vcc_data->max_pdu))) {
+                       dbg ("udsl_extract_cells: no memory for skb (vcc: 0x%p)!", 
vcc);
+                       if (pti)
+                               atomic_inc (&vcc->stats->rx_err);
+                       continue;
+               }
 
-                               /* if alloc fails, we just drop the cell. it is 
possible that we can still
-                                * receive cells on other vcc's
-                                */
-                               if (vcc->skb) {
-                                       /* if (buffer overrun) discard received cells 
until now */
-                                       if ((vcc->skb->len) > (vcc->max_pdu - 48))
-                                               skb_trim (vcc->skb, 0);
-
-                                       /* copy data */
-                                       memcpy (vcc->skb->tail, cell_payload, 48);
-                                       skb_put (vcc->skb, 48);
-
-                                       /* check for end of buffer */
-                                       if (cell [3] & 0x2) {
-                                               struct sk_buff *tmp;
-
-                                               /* the aal5 buffer ends here, cut the 
buffer. */
-                                               /* buffer will always have at least 
one whole cell, so */
-                                               /* don't need to check return from 
skb_pull */
-                                               skb_pull (skb, 53);
-                                               *ctx = vcc;
-                                               tmp = vcc->skb;
-                                               vcc->skb = NULL;
-
-                                               vdbg ("udsl_decode_rawcell returns 
ATM_AAL5 pdu 0x%p with length %d", tmp, tmp->len);
-                                               return tmp;
-                                       }
-                               }
-                               /* flush the cell */
-                               /* buffer will always contain at least one whole cell, 
so don't */
-                               /* need to check return value from skb_pull */
-                               skb_pull (skb, 53);
-                       } else {
-                               /* If data is corrupt and skb doesn't hold a whole 
cell, flush the lot */
-                               __skb_pull (skb, skb->len);
-                               return NULL;
-                       }
+               skb = vcc_data->skb;
+
+               if (skb->len + ATM_CELL_PAYLOAD > vcc_data->max_pdu) {
+                       dbg ("udsl_extract_cells: buffer overrun (max_pdu: %u, 
skb->len %u, vcc: 0x%p)", vcc_data->max_pdu, skb->len, vcc);
+                       /* discard cells already received */
+                       skb_trim (skb, 0);
+                       BUG_ON (vcc_data->max_pdu < ATM_CELL_PAYLOAD);
                }
-       }
 
-       return NULL;
-}
+               memcpy (skb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
+               __skb_put (skb, ATM_CELL_PAYLOAD);
 
-static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_buff 
*skb)
-{
-       uint crc = 0xffffffff;
-       uint length, pdu_crc, pdu_length;
+               if (pti) {
+                       length = (source [ATM_CELL_SIZE - 6] << 8) + source 
[ATM_CELL_SIZE - 5];
 
-       vdbg ("udsl_decode_aal5 (0x%p, 0x%p) called", ctx, skb);
+                       /* guard against overflow */
+                       if (length > ATM_MAX_AAL5_PDU) {
+                               dbg ("udsl_extract_cells: bogus length %u (vcc: 
0x%p)", length, vcc);
+                               goto drop;
+                       }
 
-       if (skb->len && (skb->len % 48))
-               return NULL;
+                       pdu_length = UDSL_NUM_CELLS (length) * ATM_CELL_PAYLOAD;
 
-       length = (skb->tail [-6] << 8) + skb->tail [-5];
-       pdu_crc =
-           (skb->tail [-4] << 24) + (skb->tail [-3] << 16) + (skb->tail [-2] << 8) + 
skb->tail [-1];
-       pdu_length = ((length + 47 + 8) / 48) * 48;
-
-       vdbg ("udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, 
pdu_length = %d", skb->len, length, pdu_crc, pdu_length);
-
-       /* is skb long enough ? */
-       if (skb->len < pdu_length) {
-               atomic_inc (&ctx->vcc->stats->rx_err);
-               return NULL;
-       }
+                       if (skb->len < pdu_length) {
+                               dbg ("udsl_extract_cells: bogus pdu_length %u 
(skb->len: %u, vcc: 0x%p)", pdu_length, skb->len, vcc);
+                               goto drop;
+                       }
 
-       /* is skb too long ? */
-       if (skb->len > pdu_length) {
-               dbg ("udsl_decode_aal5: Warning: readjusting illegal size %d -> %d", 
skb->len, pdu_length);
-               /* buffer is too long. we can try to recover
-                * if we discard the first part of the skb.
-                * the crc will decide whether this was ok
-                */
-               skb_pull (skb, skb->len - pdu_length);
-       }
-
-       crc = ~crc32_be (crc, skb->data, pdu_length - 4);
-
-       /* check crc */
-       if (pdu_crc != crc) {
-               dbg ("udsl_decode_aal5: crc check failed!");
-               atomic_inc (&ctx->vcc->stats->rx_err);
-               return NULL;
-       }
+                       if (crc32_be (~0, skb->tail - pdu_length, pdu_length) != 
0xc704dd7b) {
+                               dbg ("udsl_extract_cells: packet failed crc check 
(vcc: 0x%p)", vcc);
+                               goto drop;
+                       }
 
-       /* pdu is ok */
-       skb_trim (skb, length);
+                       if (!atm_charge (vcc, skb->truesize)) {
+                               dbg ("udsl_extract_cells: failed atm_charge 
(skb->truesize: %u)", skb->truesize);
+                               goto drop_no_stats; /* atm_charge increments rx_drop */
+                       }
+
+                       /* now that we are sure to send the skb, it is ok to change 
skb->data */
+                       if (skb->len > pdu_length)
+                               skb_pull (skb, skb->len - pdu_length); /* discard 
initial junk */
+
+                       skb_trim (skb, length); /* drop zero padding and trailer */
+
+                       atomic_inc (&vcc->stats->rx);
+
+                       PACKETDEBUG (skb->data, skb->len);
+
+                       vdbg ("udsl_extract_cells: sending skb 0x%p, skb->len %u, 
skb->truesize %u", skb, skb->len, skb->truesize);
 
-       /* update stats */
-       atomic_inc (&ctx->vcc->stats->rx);
+                       vcc->push (vcc, skb);
 
-       vdbg ("udsl_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len);
-       return skb;
+                       vcc_data->skb = NULL;
+
+                       continue;
+
+drop:
+                       atomic_inc (&vcc->stats->rx_err);
+drop_no_stats:
+                       skb_trim (skb, 0);
+               }
+       }
 }
 
 
@@ -500,147 +484,90 @@
 
 static void udsl_complete_receive (struct urb *urb)
 {
+       struct udsl_receive_buffer *buf;
        struct udsl_instance_data *instance;
        struct udsl_receiver *rcv;
        unsigned long flags;
 
-       if (!urb || !(rcv = urb->context) || !(instance = rcv->instance)) {
+       if (!urb || !(rcv = urb->context)) {
                dbg ("udsl_complete_receive: bad urb!");
                return;
        }
 
-       vdbg ("udsl_complete_receive entered (urb 0x%p, status %d)", urb, urb->status);
+       instance = rcv->instance;
+       buf = rcv->buffer;
+
+       buf->filled_cells = urb->actual_length / ATM_CELL_SIZE;
+
+       vdbg ("udsl_complete_receive: urb 0x%p, status %d, actual_length %d, 
filled_cells %u, rcv 0x%p, buf 0x%p", urb, urb->status, urb->actual_length, 
buf->filled_cells, rcv, buf);
+
+       BUG_ON (buf->filled_cells > UDSL_RCV_BUF_SIZE);
 
        /* may not be in_interrupt() */
-       spin_lock_irqsave (&instance->completed_receivers_lock, flags);
-       list_add_tail (&rcv->list, &instance->completed_receivers);
-       tasklet_schedule (&instance->receive_tasklet);
-       spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+       spin_lock_irqsave (&instance->receive_lock, flags);
+       list_add (&rcv->list, &instance->spare_receivers);
+       list_add_tail (&buf->list, &instance->filled_receive_buffers);
+       if (likely (!urb->status))
+               tasklet_schedule (&instance->receive_tasklet);
+       spin_unlock_irqrestore (&instance->receive_lock, flags);
 }
 
 static void udsl_process_receive (unsigned long data)
 {
+       struct udsl_receive_buffer *buf;
        struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
        struct udsl_receiver *rcv;
-       unsigned char *data_start;
-       struct sk_buff *skb;
-       struct urb *urb;
-       struct udsl_vcc_data *atmsar_vcc = NULL;
-       struct sk_buff *new = NULL, *tmp = NULL;
        int err;
 
-       vdbg ("udsl_process_receive entered");
-
-       spin_lock_irq (&instance->completed_receivers_lock);
-       while (!list_empty (&instance->completed_receivers)) {
-               rcv = list_entry (instance->completed_receivers.next, struct 
udsl_receiver, list);
-               list_del (&rcv->list);
-               spin_unlock_irq (&instance->completed_receivers_lock);
-
-               urb = rcv->urb;
-               vdbg ("udsl_process_receive: got packet %p with length %d and status 
%d", urb, urb->actual_length, urb->status);
-
-               switch (urb->status) {
-               case 0:
-                       vdbg ("udsl_process_receive: processing urb with rcv %p, urb 
%p, skb %p", rcv, urb, rcv->skb);
-
-                       /* update the skb structure */
-                       skb = rcv->skb;
-                       skb_trim (skb, 0);
-                       skb_put (skb, urb->actual_length);
-                       data_start = skb->data;
-
-                       vdbg ("skb->len = %d", skb->len);
-                       PACKETDEBUG (skb->data, skb->len);
-
-                       while ((new = udsl_decode_rawcell (instance, skb, 
&atmsar_vcc))) {
-                               vdbg ("(after cell processing)skb->len = %d", 
new->len);
-
-                               tmp = new;
-                               new = udsl_decode_aal5 (atmsar_vcc, new);
-
-                               /* we can't send NULL skbs upstream, the ATM layer 
would try to close the vcc... */
-                               if (new) {
-                                       vdbg ("(after aal5 decap) skb->len = %d", 
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 {
-                                               dbg
-                                                   ("dropping incoming packet : 
vcc->sk->rcvbuf = %d, skb->true_size = %d",
-                                                    atmsar_vcc->vcc->sk->rcvbuf, 
new->truesize);
-                                               dev_kfree_skb (new);
-                                       }
-                               } else {
-                                       dbg ("udsl_decode_aal5 returned NULL!");
-                                       dev_kfree_skb (tmp);
-                               }
-                       }
-
-                       /* restore skb */
-                       skb_push (skb, skb->data - data_start);
-
-                       FILL_BULK_URB (urb,
-                                      instance->usb_dev,
-                                      usb_rcvbulkpipe (instance->usb_dev, 
UDSL_ENDPOINT_DATA_IN),
-                                      (unsigned char *) rcv->skb->data,
-                                      UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE,
-                                      udsl_complete_receive,
-                                      rcv);
-                       urb->transfer_flags |= USB_QUEUE_BULK;
-                       if (!(err = usb_submit_urb (urb)))
-                               break;
-                       dbg ("udsl_process_receive: submission failed (%d)", err);
-                       /* fall through */
-               default: /* error or urb unlinked */
-                       vdbg ("udsl_process_receive: adding to spare_receivers");
-                       spin_lock_irq (&instance->spare_receivers_lock);
-                       list_add (&rcv->list, &instance->spare_receivers);
-                       spin_unlock_irq (&instance->spare_receivers_lock);
+made_progress:
+       while (!list_empty (&instance->spare_receive_buffers)) {
+               spin_lock_irq (&instance->receive_lock);
+               if (list_empty (&instance->spare_receivers)) {
+                       spin_unlock_irq (&instance->receive_lock);
                        break;
-               } /* switch */
-
-               spin_lock_irq (&instance->completed_receivers_lock);
-       } /* while */
-       spin_unlock_irq (&instance->completed_receivers_lock);
-       vdbg ("udsl_process_receive successful");
-}
-
-static void udsl_fire_receivers (struct udsl_instance_data *instance)
-{
-       struct list_head receivers, *pos, *n;
-
-       INIT_LIST_HEAD (&receivers);
-
-       down (&instance->serialize);
-
-       spin_lock_irq (&instance->spare_receivers_lock);
-       list_splice_init (&instance->spare_receivers, &receivers);
-       spin_unlock_irq (&instance->spare_receivers_lock);
+               }
+               rcv = list_entry (instance->spare_receivers.next, struct 
udsl_receiver, list);
+               list_del (&rcv->list);
+               spin_unlock_irq (&instance->receive_lock);
 
-       list_for_each_safe (pos, n, &receivers) {
-               struct udsl_receiver *rcv = list_entry (pos, struct udsl_receiver, 
list);
+               buf = list_entry (instance->spare_receive_buffers.next, struct 
udsl_receive_buffer, list);
+               list_del (&buf->list);
 
-               dbg ("udsl_fire_receivers: firing urb %p", rcv->urb);
+               rcv->buffer = buf;
 
                FILL_BULK_URB (rcv->urb,
                               instance->usb_dev,
                               usb_rcvbulkpipe (instance->usb_dev, 
UDSL_ENDPOINT_DATA_IN),
-                              (unsigned char *) rcv->skb->data,
+                              buf->base,
                               UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE,
                               udsl_complete_receive,
                               rcv);
                rcv->urb->transfer_flags |= USB_QUEUE_BULK;
 
-               if (usb_submit_urb (rcv->urb) < 0) {
-                       dbg ("udsl_fire_receivers: submit failed!");
-                       spin_lock_irq (&instance->spare_receivers_lock);
-                       list_move (pos, &instance->spare_receivers);
-                       spin_unlock_irq (&instance->spare_receivers_lock);
+               vdbg ("udsl_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p", 
rcv->urb, rcv, buf);
+
+               if ((err = usb_submit_urb(rcv->urb)) < 0) {
+                       dbg ("udsl_process_receive: urb submission failed (%d)!", err);
+                       list_add (&buf->list, &instance->spare_receive_buffers);
+                       spin_lock_irq (&instance->receive_lock);
+                       list_add (&rcv->list, &instance->spare_receivers);
+                       spin_unlock_irq (&instance->receive_lock);
+                       break;
                }
        }
 
-       up (&instance->serialize);
+       spin_lock_irq (&instance->receive_lock);
+       if (list_empty (&instance->filled_receive_buffers)) {
+               spin_unlock_irq (&instance->receive_lock);
+               return; /* done - no more buffers */
+       }
+       buf = list_entry (instance->filled_receive_buffers.next, struct 
udsl_receive_buffer, list);
+       list_del (&buf->list);
+       spin_unlock_irq (&instance->receive_lock);
+       vdbg ("udsl_process_receive: processing buf 0x%p", buf);
+       udsl_extract_cells (instance, buf->base, buf->filled_cells);
+       list_add (&buf->list, &instance->spare_receive_buffers);
+       goto made_progress;
 }
 
 
@@ -842,6 +769,7 @@
 
        dbg ("udsl_atm_dev_close: queue has %u elements", instance->sndqueue.qlen);
 
+       tasklet_kill (&instance->receive_tasklet);
        tasklet_kill (&instance->send_tasklet);
        kfree (instance);
        dev->dev_data = NULL;
@@ -916,7 +844,7 @@
                return -EINVAL;
 
        /* only support AAL5 */
-       if (vcc->qos.aal != ATM_AAL5 || vcc->qos.rxtp.max_sdu < 0 || 
vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)
+       if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0) || 
(vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU))
                return -EINVAL;
 
        if (!instance->firmware_loaded) {
@@ -960,7 +888,7 @@
 
        up (&instance->serialize);
 
-       udsl_fire_receivers (instance);
+       tasklet_schedule (&instance->receive_tasklet);
 
        dbg ("udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)", new, 
new->max_pdu);
 
@@ -1038,7 +966,9 @@
                instance->firmware_loaded = 1;
        }
        up (&instance->serialize);
-       udsl_fire_receivers (instance);
+
+       tasklet_schedule (&instance->receive_tasklet);
+
        return 0;
 }
 
@@ -1097,13 +1027,12 @@
 
        INIT_LIST_HEAD (&instance->vcc_list);
 
-       spin_lock_init (&instance->spare_receivers_lock);
+       spin_lock_init (&instance->receive_lock);
        INIT_LIST_HEAD (&instance->spare_receivers);
-
-       spin_lock_init (&instance->completed_receivers_lock);
-       INIT_LIST_HEAD (&instance->completed_receivers);
+       INIT_LIST_HEAD (&instance->filled_receive_buffers);
 
        tasklet_init (&instance->receive_tasklet, udsl_process_receive, (unsigned 
long) instance);
+       INIT_LIST_HEAD (&instance->spare_receive_buffers);
 
        skb_queue_head_init (&instance->sndqueue);
 
@@ -1118,11 +1047,6 @@
        for (i = 0; i < UDSL_NUM_RCV_URBS; i++) {
                struct udsl_receiver *rcv = &(instance->receivers [i]);
 
-               if (!(rcv->skb = dev_alloc_skb (UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE))) {
-                       dbg ("udsl_usb_probe: no memory for skb %d!", i);
-                       goto fail;
-               }
-
                if (!(rcv->urb = usb_alloc_urb (0))) {
                        dbg ("udsl_usb_probe: no memory for receive urb %d!", i);
                        goto fail;
@@ -1131,8 +1055,17 @@
                rcv->instance = instance;
 
                list_add (&rcv->list, &instance->spare_receivers);
+       }
+
+       for (i = 0; i < UDSL_NUM_RCV_BUFS; i++) {
+               struct udsl_receive_buffer *buf = &(instance->receive_buffers [i]);
+
+               if (!(buf->base = kmalloc (UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE, 
GFP_KERNEL))) {
+                       dbg ("udsl_usb_probe: no memory for receive buffer %d!", i);
+                       goto fail;
+               }
 
-               dbg ("udsl_usb_probe: skb->truesize = %d (asked for %d)", 
rcv->skb->truesize, UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE);
+               list_add (&buf->list, &instance->spare_receive_buffers);
        }
 
        /* send init */
@@ -1215,14 +1148,11 @@
        for (i = 0; i < UDSL_NUM_SND_URBS; i++)
                usb_free_urb (instance->senders [i].urb);
 
-       for (i = 0; i < UDSL_NUM_RCV_URBS; i++) {
-               struct udsl_receiver *rcv = &(instance->receivers [i]);
-
-               usb_free_urb (rcv->urb);
+       for (i = 0; i < UDSL_NUM_RCV_BUFS; i++)
+               kfree (instance->receive_buffers [i].base);
 
-               if (rcv->skb)
-                       dev_kfree_skb (rcv->skb);
-       }
+       for (i = 0; i < UDSL_NUM_RCV_URBS; i++)
+               usb_free_urb (instance->receivers [i].urb);
 
        kfree (instance);
 
@@ -1233,7 +1163,7 @@
 {
        struct udsl_instance_data *instance = ptr;
        struct list_head *pos;
-       unsigned int count = 0;
+       unsigned int count;
        int result, i;
 
        dbg ("udsl_usb_disconnect entered");
@@ -1243,20 +1173,8 @@
                return;
        }
 
-       tasklet_disable (&instance->receive_tasklet);
-
        /* receive finalize */
-       down (&instance->serialize); /* vs udsl_fire_receivers */
-       /* no need to take the spinlock */
-       list_for_each (pos, &instance->spare_receivers)
-               if (++count > UDSL_NUM_RCV_URBS)
-                       panic (__FILE__ ": memory corruption detected at line %d!\n", 
__LINE__);
-       INIT_LIST_HEAD (&instance->spare_receivers);
-       up (&instance->serialize);
-
-       dbg ("udsl_usb_disconnect: flushed %u spare receivers", count);
-
-       count = UDSL_NUM_RCV_URBS - count;
+       tasklet_disable (&instance->receive_tasklet);
 
        for (i = 0; i < UDSL_NUM_RCV_URBS; i++)
                if ((result = usb_unlink_urb (instance->receivers [i].urb)) < 0)
@@ -1264,17 +1182,16 @@
 
        /* wait for completion handlers to finish */
        do {
-               unsigned int completed = 0;
-
-               spin_lock_irq (&instance->completed_receivers_lock);
-               list_for_each (pos, &instance->completed_receivers)
-                       if (++completed > count)
+               count = 0;
+               spin_lock_irq (&instance->receive_lock);
+               list_for_each (pos, &instance->spare_receivers)
+                       if (++count > UDSL_NUM_RCV_URBS)
                                panic (__FILE__ ": memory corruption detected at line 
%d!\n", __LINE__);
-               spin_unlock_irq (&instance->completed_receivers_lock);
+               spin_unlock_irq (&instance->receive_lock);
 
-               dbg ("udsl_usb_disconnect: found %u completed receivers", completed);
+               dbg ("udsl_usb_disconnect: found %u spare receivers", count);
 
-               if (completed == count)
+               if (count == UDSL_NUM_RCV_URBS)
                        break;
 
                set_current_state (TASK_RUNNING);
@@ -1282,17 +1199,16 @@
        } while (1);
 
        /* no need to take the spinlock */
-       INIT_LIST_HEAD (&instance->completed_receivers);
+       INIT_LIST_HEAD (&instance->filled_receive_buffers);
+       INIT_LIST_HEAD (&instance->spare_receive_buffers);
 
        tasklet_enable (&instance->receive_tasklet);
-       tasklet_kill (&instance->receive_tasklet);
 
-       for (i = 0; i < UDSL_NUM_RCV_URBS; i++) {
-               struct udsl_receiver *rcv = &(instance->receivers [i]);
+       for (i = 0; i < UDSL_NUM_RCV_URBS; i++)
+               usb_free_urb (instance->receivers [i].urb);
 
-               usb_free_urb (rcv->urb);
-               dev_kfree_skb (rcv->skb);
-       }
+       for (i = 0; i < UDSL_NUM_RCV_BUFS; i++)
+               kfree (instance->receive_buffers [i].base);
 
        /* send finalize */
        tasklet_disable (&instance->send_tasklet);
@@ -1336,7 +1252,7 @@
        instance->usb_dev = NULL;
 
        /* ATM finalize */
-       shutdown_atm_dev (instance->atm_dev); /* frees instance */
+       shutdown_atm_dev (instance->atm_dev); /* frees instance, kills tasklets */
 }
 
 



-------------------------------------------------------
This SF.Net email is sponsored by: INetU
Attention Web Developers & Consultants: Become An INetU Hosting Partner.
Refer Dedicated Servers. We Manage Them. You Get 10% Monthly Commission!
INetU Dedicated Managed Hosting http://www.inetu.net/partner/index.php
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to