On Tue, 5 Mar 2002, Greg KH wrote:

> On Tue, Mar 05, 2002 at 10:40:59AM -0800, Greg KH wrote:
> > 
> > Ah, that's it.  include/net/irda/irda-usb.h was missed in the big "no
> > more static urb allocations" fixup.  Give me a few minutes to change
> > this.
> 
> Jean, does the patch below fix your problem?
> 
[...]
> -     urb = &self->speed_urb;
> +     urb = self->speed_urb;

Hi Greg and Jean,

I haven't tried the patch but I'm sure the problem is more than this:

Besides the dynamic alloc enforcement there was the memflag change for
usb_submit_urb() as well. irda-usb calls this either with spinlock held or
from places which are either in process context or interrupt (resubmit on
rx-urb completion). Hence GFP_KERNEL isn't a good choice here.

Did some band-aid on it to address both issues:
- all embedded urb's (tx_urb, speed_urb, rx_urb[] pool) changed to
  struct urb * in the control block. This is basically a modified version
  of your patch, however the usb_alloc_urb()/usb_free_urb() are moved
  from probe/disconnect to the netdev->open() and close() path
  respectively. This is because I'm unsure whether there are disconnect
  races: If the urb's are free'd on disconnect, are we sure netdev->xmit
  wouldn't try to use them?
- changed memflags when calling usb_submit_urb() to either GFP_ATOMIC
  unconditionally when inside spinlock or depending on 
  in_interrupt() otherwise.

With the patch below things seem to work for me on OHCI - at least
discovery is fine from both ends. Patch is meant for 2.5.5 final or
later. However, I had only 2.5.5-pre1 ready for fast application
hence it was tried this way - with the memflags in usb_alloc_urb()
backed out - AFAICS it's the only change thereafter.
Furthermore, an additional isa_virt_to_bus() update is required for
net/irda/irda_device.c to get things rolling for any recent 2.5.x.

Martin

-----------------------------------------

--- linux-2.5.5-pre1/include/net/irda/irda-usb.h        Wed Nov 28 15:17:28 2001
+++ v2.5.5-pre1-md/include/net/irda/irda-usb.h  Wed Mar  6 00:09:36 2002
@@ -139,10 +139,10 @@
 
        wait_queue_head_t wait_q;       /* for timeouts */
 
-       struct urb rx_urb[IU_MAX_RX_URBS];      /* URBs used to receive data frames */
+       struct urb *rx_urb[IU_MAX_RX_URBS];     /* URBs used to receive data frames */
        struct urb *idle_rx_urb;        /* Pointer to idle URB in Rx path */
-       struct urb tx_urb;              /* URB used to send data frames */
-       struct urb speed_urb;           /* URB used to send speed commands */
+       struct urb *tx_urb;             /* URB used to send data frames */
+       struct urb *speed_urb;          /* URB used to send speed commands */
        
        struct net_device *netdev;      /* Yes! we are some kind of netdev. */
        struct net_device_stats stats;
--- linux-2.5.5-pre1/drivers/net/irda/irda-usb.c        Tue Feb 19 14:46:17 2002
+++ v2.5.5-pre1-md/drivers/net/irda/irda-usb.c  Wed Mar  6 01:21:51 2002
@@ -255,7 +255,7 @@
                   self->new_speed, self->new_xbofs);
 
        /* Grab the speed URB */
-       urb = &self->speed_urb;
+       urb = self->speed_urb;
        if (urb->status != 0) {
                WARNING(__FUNCTION__ "(), URB still in use!\n");
                return;
@@ -278,7 +278,7 @@
        urb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
        urb->timeout = MSECS_TO_JIFFIES(100);
 
-       if ((ret = usb_submit_urb(urb, GFP_KERNEL))) {
+       if ((ret = usb_submit_urb(urb, GFP_ATOMIC))) {  /* under spinlock! */
                WARNING(__FUNCTION__ "(), failed Speed URB\n");
        }
        spin_unlock_irqrestore(&self->lock, flags);
@@ -317,7 +317,7 @@
        urb->status = 0;
 
        /* If it was the speed URB, allow the stack to send more packets */
-       if(urb == &self->speed_urb) {
+       if(urb == self->speed_urb) {
                netif_wake_queue(self->netdev);
        }
 }
@@ -329,7 +329,7 @@
 static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct irda_usb_cb *self = netdev->priv;
-       struct urb *urb = &self->tx_urb;
+       struct urb *urb = self->tx_urb;
        unsigned long flags;
        s32 speed;
        s16 xbofs;
@@ -451,7 +451,7 @@
        }
        
        /* Ask USB to send the packet */
-       if ((res = usb_submit_urb(urb, GFP_KERNEL))) {
+       if ((res = usb_submit_urb(urb, GFP_ATOMIC))) {  /* under spinlock */
                WARNING(__FUNCTION__ "(), failed Tx URB\n");
                self->stats.tx_errors++;
                /* Let USB recover : We will catch that in the watchdog */
@@ -546,7 +546,7 @@
        }
 
        /* Check speed URB */
-       urb = &(self->speed_urb);
+       urb = self->speed_urb;
        if (urb->status != 0) {
                IRDA_DEBUG(0, "%s: Speed change timed out, urb->status=%d, 
urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags);
 
@@ -571,7 +571,7 @@
        }
 
        /* Check Tx URB */
-       urb = &(self->tx_urb);
+       urb = self->tx_urb;
        if (urb->status != 0) {
                struct sk_buff *skb = urb->context;
 
@@ -730,7 +730,8 @@
        urb->status = 0;
        urb->next = NULL;       /* Don't auto resubmit URBs */
        
-       ret = usb_submit_urb(urb, GFP_KERNEL);
+       /* called both from netdev->open _and_ urb_complete isr!*/
+       ret = usb_submit_urb(urb, (in_interrupt()) ? GFP_ATOMIC : GFP_KERNEL);
        if (ret) {
                /* If this ever happen, we are in deep s***.
                 * Basically, the Rx path will stop... */
@@ -915,7 +916,7 @@
 {
        struct irda_usb_cb *self;
        char    hwname[16];
-       int i;
+       int i, j;
        
        IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
@@ -936,6 +937,34 @@
        self->new_speed = -1;
        self->new_xbofs = -1;
 
+       /* allocate our urbs */
+       self->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!self->speed_urb) {
+               WARNING("%s, speed urb alloc failed\n", __FUNCTION__);
+               return -ENOMEM;
+       }
+       self->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!self->tx_urb) {
+               WARNING("%s, tx urb alloc failed\n", __FUNCTION__);
+               usb_free_urb(self->speed_urb);
+               self->speed_urb = NULL;
+               return -ENOMEM;
+       }
+       for (i = 0; i < IU_MAX_RX_URBS; i++) {  /* including idle_urb! */
+               self->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+               if (!self->rx_urb[i]) {
+                       WARNING("%s, rx urb pool alloc failed\n", __FUNCTION__);
+                       for (j = 0; j < i; j++) {
+                               usb_free_urb(self->rx_urb[j]);
+                               self->rx_urb[j] = NULL;
+                       }
+                       usb_free_urb(self->speed_urb);
+                       usb_free_urb(self->tx_urb);
+                       self->speed_urb = self->tx_urb = NULL;
+                       return -ENOMEM;
+               }
+       }
+
        /* To do *before* submitting Rx urbs and starting net Tx queue
         * Jean II */
        self->netopen = 1;
@@ -955,9 +984,9 @@
        /* Now that we can pass data to IrLAP, allow the USB layer
         * to send us some data... */
        for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++)
-               irda_usb_submit(self, NULL, &(self->rx_urb[i]));
+               irda_usb_submit(self, NULL, self->rx_urb[i]);
        /* Note : we submit all the Rx URB except for one - Jean II */
-       self->idle_rx_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
+       self->idle_rx_urb = self->rx_urb[IU_MAX_ACTIVE_RX_URBS];
        self->idle_rx_urb->context = NULL;
 
        /* Ready to play !!! */
@@ -992,7 +1021,7 @@
 
        /* 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]);
+               struct urb *urb = self->rx_urb[i];
                struct sk_buff *skb = (struct sk_buff *) urb->context;
                /* Cancel the receive command */
                usb_unlink_urb(urb);
@@ -1003,14 +1032,24 @@
                }
        }
        /* Cancel Tx and speed URB */
-       usb_unlink_urb(&(self->tx_urb));
-       usb_unlink_urb(&(self->speed_urb));
+       usb_unlink_urb(self->tx_urb);
+       usb_unlink_urb(self->speed_urb);
 
        /* Stop and remove instance of IrLAP */
        if (self->irlap)
                irlap_close(self->irlap);
        self->irlap = NULL;
 
+       /* free all the urbs - above are all synchrous unlinks! */
+
+       for (i = 0; i < IU_MAX_RX_URBS; i++) { /* including idle_urb! */
+               usb_free_urb(self->rx_urb[i]);
+               self->rx_urb[i] = NULL;
+       }
+       usb_free_urb(self->tx_urb);
+       usb_free_urb(self->speed_urb);
+       self->tx_urb = self->speed_urb = NULL;
+
        MOD_DEC_USE_COUNT;
 
        return 0;
@@ -1501,10 +1540,10 @@
                netif_stop_queue(self->netdev);
                /* Stop all the receive URBs */
                for (i = 0; i < IU_MAX_RX_URBS; i++)
-                       usb_unlink_urb(&(self->rx_urb[i]));
+                       usb_unlink_urb(self->rx_urb[i]);
                /* Cancel Tx and speed URB */
-               usb_unlink_urb(&(self->tx_urb));
-               usb_unlink_urb(&(self->speed_urb));
+               usb_unlink_urb(self->tx_urb);
+               usb_unlink_urb(self->speed_urb);
 
                IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is 
still active...\n");
                /* better not do anything just yet, usb_irda_cleanup()



_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to