X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Firda%2Firda-usb.c;h=6e2ec56cde0b1042d4c5b65289295abeca74a4a8;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=46e0022d3258ab3c870cf62e70a211c06a99d1ef;hpb=cace1c4618b6c6442b7dc973e935e7f3268e4aa7;p=linux-2.6.git diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 46e0022d3..6e2ec56cd 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -108,6 +108,7 @@ static void irda_usb_close(struct irda_usb_cb *self); static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs); static void write_bulk_callback(struct urb *urb, struct pt_regs *regs); static void irda_usb_receive(struct urb *urb, struct pt_regs *regs); +static void irda_usb_rx_defer_expired(unsigned long data); static int irda_usb_net_open(struct net_device *dev); static int irda_usb_net_close(struct net_device *dev); static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); @@ -267,7 +268,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self) frame, IRDA_USB_SPEED_MTU, speed_bulk_callback, self); urb->transfer_buffer_length = USB_IRDA_HEADER; - urb->transfer_flags = URB_ASYNC_UNLINK; + urb->transfer_flags = 0; /* Irq disabled -> GFP_ATOMIC */ if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) { @@ -401,15 +402,12 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) skb->data, IRDA_SKB_MAX_MTU, write_bulk_callback, skb); urb->transfer_buffer_length = skb->len; - /* Note : unlink *must* be Asynchronous because of the code in - * irda_usb_net_timeout() -> call in irq - Jean II */ - urb->transfer_flags = URB_ASYNC_UNLINK; /* This flag (URB_ZERO_PACKET) indicates that what we send is not * a continuous stream of data but separate packets. * In this case, the USB layer will insert an empty USB frame (TD) * after each of our packets that is exact multiple of the frame size. * This is how the dongle will detect the end of packet - Jean II */ - urb->transfer_flags |= URB_ZERO_PACKET; + urb->transfer_flags = URB_ZERO_PACKET; /* Generate min turn time. FIXME: can we do better than this? */ /* Trying to a turnaround time at this level is trying to measure @@ -630,8 +628,6 @@ static void irda_usb_net_timeout(struct net_device *netdev) * in completion handler, because urb->status will * be -ENOENT. We will fix that at the next watchdog, * leaving more time to USB to recover... - * Also, we are in interrupt, so we need to have - * URB_ASYNC_UNLINK to work properly... * Jean II */ done = 1; break; @@ -682,6 +678,12 @@ static void irda_usb_net_timeout(struct net_device *netdev) * on the interrupt pipe and hang the Rx URB only when an interrupt is * received. * Jean II + * + * Note : don't read the above as what we are currently doing, but as + * something we could do with KC dongle. Also don't forget that the + * interrupt pipe is not part of the original standard, so this would + * need to be optional... + * Jean II */ /*------------------------------------------------------------------*/ @@ -709,10 +711,8 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struc /* Reinitialize URB */ usb_fill_bulk_urb(urb, self->usbdev, usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), - skb->data, skb->truesize, + skb->data, IRDA_SKB_MAX_MTU, irda_usb_receive, skb); - /* Note : unlink *must* be synchronous because of the code in - * irda_usb_net_close() -> free the skb - Jean II */ urb->status = 0; /* Can be called from irda_usb_receive (irq handler) -> GFP_ATOMIC */ @@ -739,7 +739,8 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) struct irda_skb_cb *cb; struct sk_buff *newskb; struct sk_buff *dataskb; - int docopy; + struct urb *next_urb; + unsigned int len, docopy; IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length); @@ -760,20 +761,37 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) if (urb->status != 0) { switch (urb->status) { case -EILSEQ: - self->stats.rx_errors++; self->stats.rx_crc_errors++; - break; + /* Also precursor to a hot-unplug on UHCI. */ + /* Fallthrough... */ case -ECONNRESET: /* -104 */ - IRDA_DEBUG(0, "%s(), Connection Reset (-104), transfer_flags 0x%04X \n", __FUNCTION__, urb->transfer_flags); + /* Random error, if I remember correctly */ /* uhci_cleanup_unlink() is going to kill the Rx * URB just after we return. No problem, at this * point the URB will be idle ;-) - Jean II */ - break; + case -ESHUTDOWN: /* -108 */ + /* That's usually a hot-unplug. Submit will fail... */ + case -ETIMEDOUT: /* -110 */ + /* Usually precursor to a hot-unplug on OHCI. */ default: - IRDA_DEBUG(0, "%s(), RX status %d,transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags); + self->stats.rx_errors++; + IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __FUNCTION__, urb->status, urb->transfer_flags); break; } - goto done; + /* If we received an error, we don't want to resubmit the + * Rx URB straight away but to give the USB layer a little + * bit of breathing room. + * We are in the USB thread context, therefore there is a + * danger of recursion (new URB we submit fails, we come + * back here). + * With recent USB stack (2.6.15+), I'm seeing that on + * hot unplug of the dongle... + * Lowest effective timer is 10ms... + * Jean II */ + self->rx_defer_timer.function = &irda_usb_rx_defer_expired; + self->rx_defer_timer.data = (unsigned long) urb; + mod_timer(&self->rx_defer_timer, jiffies + (10 * HZ / 1000)); + return; } /* Check for empty frames */ @@ -833,10 +851,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) dataskb->dev = self->netdev; dataskb->mac.raw = dataskb->data; dataskb->protocol = htons(ETH_P_IRDA); + len = dataskb->len; netif_rx(dataskb); /* Keep stats up to date */ - self->stats.rx_bytes += dataskb->len; + self->stats.rx_bytes += len; self->stats.rx_packets++; self->netdev->last_rx = jiffies; @@ -850,13 +869,45 @@ done: * idle slot.... * Jean II */ /* Note : with this scheme, we could submit the idle URB before - * processing the Rx URB. Another time... Jean II */ + * processing the Rx URB. I don't think it would buy us anything as + * we are running in the USB thread context. Jean II */ + next_urb = self->idle_rx_urb; - /* Submit the idle URB to replace the URB we've just received */ - irda_usb_submit(self, skb, self->idle_rx_urb); /* Recycle Rx URB : Now, the idle URB is the present one */ urb->context = NULL; self->idle_rx_urb = urb; + + /* Submit the idle URB to replace the URB we've just received. + * Do it last to avoid race conditions... Jean II */ + irda_usb_submit(self, skb, next_urb); +} + +/*------------------------------------------------------------------*/ +/* + * In case of errors, we want the USB layer to have time to recover. + * Now, it is time to resubmit ouur Rx URB... + */ +static void irda_usb_rx_defer_expired(unsigned long data) +{ + struct urb *urb = (struct urb *) data; + struct sk_buff *skb = (struct sk_buff *) urb->context; + struct irda_usb_cb *self; + struct irda_skb_cb *cb; + struct urb *next_urb; + + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + + /* Find ourselves */ + cb = (struct irda_skb_cb *) skb->cb; + IRDA_ASSERT(cb != NULL, return;); + self = (struct irda_usb_cb *) cb->context; + IRDA_ASSERT(self != NULL, return;); + + /* Same stuff as when Rx is done, see above... */ + next_urb = self->idle_rx_urb; + urb->context = NULL; + self->idle_rx_urb = urb; + irda_usb_submit(self, skb, next_urb); } /*------------------------------------------------------------------*/ @@ -995,6 +1046,9 @@ static int irda_usb_net_close(struct net_device *netdev) /* Stop network Tx queue */ netif_stop_queue(netdev); + /* Kill defered Rx URB */ + del_timer(&self->rx_defer_timer); + /* Deallocate all the Rx path buffers (URBs and skb) */ for (i = 0; i < IU_MAX_RX_URBS; i++) { struct urb *urb = self->rx_urb[i]; @@ -1008,9 +1062,7 @@ static int irda_usb_net_close(struct net_device *netdev) } } /* Cancel Tx and speed URB - need to be synchronous to avoid races */ - self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK; usb_kill_urb(self->tx_urb); - self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK; usb_kill_urb(self->speed_urb); /* Stop and remove instance of IrLAP */ @@ -1175,10 +1227,8 @@ static inline void irda_usb_close(struct irda_usb_cb *self) unregister_netdev(self->netdev); /* Remove the speed buffer */ - if (self->speed_buff != NULL) { - kfree(self->speed_buff); - self->speed_buff = NULL; - } + kfree(self->speed_buff); + self->speed_buff = NULL; } /********************** USB CONFIG SUBROUTINES **********************/ @@ -1374,6 +1424,7 @@ static int irda_usb_probe(struct usb_interface *intf, self = net->priv; self->netdev = net; spin_lock_init(&self->lock); + init_timer(&self->rx_defer_timer); /* Create all of the needed urbs */ for (i = 0; i < IU_MAX_RX_URBS; i++) { @@ -1507,6 +1558,9 @@ static void irda_usb_disconnect(struct usb_interface *intf) * This will stop/desactivate the Tx path. - Jean II */ self->present = 0; + /* Kill defered Rx URB */ + del_timer(&self->rx_defer_timer); + /* We need to have irq enabled to unlink the URBs. That's OK, * at this point the Tx path is gone - Jean II */ spin_unlock_irqrestore(&self->lock, flags); @@ -1516,14 +1570,12 @@ static void irda_usb_disconnect(struct usb_interface *intf) /* Accept no more transmissions */ /*netif_device_detach(self->netdev);*/ netif_stop_queue(self->netdev); - /* Stop all the receive URBs */ + /* Stop all the receive URBs. Must be synchronous. */ for (i = 0; i < IU_MAX_RX_URBS; i++) usb_kill_urb(self->rx_urb[i]); /* Cancel Tx and speed URB. - * Toggle flags to make sure it's synchronous. */ - self->tx_urb->transfer_flags &= ~URB_ASYNC_UNLINK; + * Make sure it's synchronous to avoid races. */ usb_kill_urb(self->tx_urb); - self->speed_urb->transfer_flags &= ~URB_ASYNC_UNLINK; usb_kill_urb(self->speed_urb); } @@ -1550,7 +1602,6 @@ static void irda_usb_disconnect(struct usb_interface *intf) * USB device callbacks */ static struct usb_driver irda_driver = { - .owner = THIS_MODULE, .name = "irda-usb", .probe = irda_usb_probe, .disconnect = irda_usb_disconnect,