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