From: David Brownell <[EMAIL PROTECTED]> Date: Thu, 05 Dec 2002 20:55:23 -0800
> EHCI is problematic here, as it does the URB > work in a tasklet :( we need to decide whether > we can move the normal URB completion back into > the hw interrupt handler or not It's worked fine so far ... but simpler would be fine too, and I'd take a patch for this. Here ya go: --- ./drivers/usb/host/ehci.h.~1~ Mon Dec 9 14:06:42 2002 +++ ./drivers/usb/host/ehci.h Mon Dec 9 14:06:50 2002 @@ -65,9 +65,6 @@ struct ehci_hcd { /* one per controlle int next_uframe; /* scan periodic, start here */ unsigned periodic_sched; /* periodic activity count */ - /* deferred work from IRQ, etc */ - struct tasklet_struct tasklet; - /* per root hub port */ unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; --- ./drivers/usb/host/ehci-q.c.~1~ Mon Dec 9 14:10:59 2002 +++ ./drivers/usb/host/ehci-q.c Mon Dec 9 14:19:03 2002 @@ -159,7 +159,7 @@ static inline void qtd_copy_status (stru } } -static void ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb) +static void ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs +*regs) { if (likely (urb->hcpriv != 0)) { struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; @@ -191,7 +191,7 @@ static void ehci_urb_done (struct ehci_h /* complete() can reenter this HCD */ spin_unlock (&ehci->lock); - usb_hcd_giveback_urb (&ehci->hcd, urb, NULL); + usb_hcd_giveback_urb (&ehci->hcd, urb, regs); spin_lock (&ehci->lock); } @@ -203,7 +203,7 @@ static void ehci_urb_done (struct ehci_h * indicating how much "real" work we did. */ static unsigned -qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) +qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) { struct ehci_qtd *qtd, *last; struct list_head *next, *qtd_list = &qh->qtd_list; @@ -225,7 +225,7 @@ qh_completions (struct ehci_hcd *ehci, s /* clean up any state from previous QTD ...*/ if (last) { if (likely (last->urb != urb)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done (ehci, last->urb, regs); count++; } ehci_qtd_free (ehci, last); @@ -311,7 +311,7 @@ qh_completions (struct ehci_hcd *ehci, s /* last urb's completion might still need calling */ if (likely (last != 0)) { - ehci_urb_done (ehci, last->urb); + ehci_urb_done (ehci, last->urb, regs); count++; ehci_qtd_free (ehci, last); } @@ -879,7 +879,7 @@ submit_async ( /* the async qh for the qtds being reclaimed are now unlinked from the HC */ /* caller must not own ehci->lock */ -static void end_unlink_async (struct ehci_hcd *ehci) +static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs) { struct ehci_qh *qh = ehci->reclaim; @@ -891,7 +891,7 @@ static void end_unlink_async (struct ehc ehci->reclaim = 0; ehci->reclaim_ready = 0; - qh_completions (ehci, qh); + qh_completions (ehci, qh, regs); if (!list_empty (&qh->qtd_list) && HCD_IS_RUNNING (ehci->hcd.state)) @@ -943,7 +943,7 @@ static void start_unlink_async (struct e if (unlikely (ehci->hcd.state == USB_STATE_HALT)) { ehci->reclaim_ready = 1; - tasklet_schedule (&ehci->tasklet); + __ehci_work (ehci, NULL); return; } @@ -966,7 +966,7 @@ static void start_unlink_async (struct e /*-------------------------------------------------------------------------*/ static void -scan_async (struct ehci_hcd *ehci) +scan_async (struct ehci_hcd *ehci, struct pt_regs *regs) { struct ehci_qh *qh; unsigned count; @@ -982,7 +982,7 @@ rescan: qh = qh_get (qh); /* concurrent unlink could happen here */ - count += qh_completions (ehci, qh); + count += qh_completions (ehci, qh, regs); qh_put (ehci, qh); goto rescan; } --- ./drivers/usb/host/ehci-hcd.c.~1~ Mon Dec 9 14:06:42 2002 +++ ./drivers/usb/host/ehci-hcd.c Mon Dec 9 14:18:23 2002 @@ -241,6 +241,9 @@ static void ehci_ready (struct ehci_hcd ehci->hcd.state = USB_STATE_READY; } +static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); +static void __ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs); + /*-------------------------------------------------------------------------*/ #include "ehci-hub.c" @@ -250,8 +253,6 @@ static void ehci_ready (struct ehci_hcd /*-------------------------------------------------------------------------*/ -static void ehci_tasklet (unsigned long param); - static void ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs); static void ehci_watchdog (unsigned long param) @@ -426,9 +427,6 @@ static int ehci_start (struct usb_hcd *h /* set async sleep time = 10 us ... ? */ - ehci->tasklet.func = ehci_tasklet; - ehci->tasklet.data = (unsigned long) ehci; - init_timer (&ehci->watchdog); ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; @@ -506,8 +504,7 @@ static void ehci_stop (struct usb_hcd *h remove_debug_files (ehci); /* root hub is shut down separately (first, when possible) */ - tasklet_disable (&ehci->tasklet); - ehci_tasklet ((unsigned long) ehci); + ehci_work (ehci, NULL); ehci_mem_cleanup (ehci); #ifdef EHCI_STATS @@ -615,21 +612,22 @@ dbg ("%s: resume port %d", hcd_to_bus (h /*-------------------------------------------------------------------------*/ /* - * tasklet scheduled by some interrupts and other events - * calls driver completion functions ... but not in_irq() + * work run by some interrupts and other events + * calls driver completion functions */ -static void ehci_tasklet (unsigned long param) +static void __ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) { - struct ehci_hcd *ehci = (struct ehci_hcd *) param; - - spin_lock_irq (&ehci->lock); - if (ehci->reclaim_ready) - end_unlink_async (ehci); - scan_async (ehci); + end_unlink_async (ehci, regs); + scan_async (ehci, regs); if (ehci->next_uframe != -1) - scan_periodic (ehci); + scan_periodic (ehci, regs); +} +static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) +{ + spin_lock_irq (&ehci->lock); + __ehci_work(ehci, regs); spin_unlock_irq (&ehci->lock); } @@ -693,7 +691,7 @@ dead: /* most work doesn't need to be in_irq() */ if (likely (bh == 1)) - tasklet_schedule (&ehci->tasklet); + ehci_work (ehci, regs); } /*-------------------------------------------------------------------------*/ @@ -799,7 +797,7 @@ static int ehci_urb_dequeue (struct usb_ intr_deschedule (ehci, qh, 1); /* qh_state == IDLE */ } - qh_completions (ehci, qh); + qh_completions (ehci, qh, NULL); /* reschedule QH iff another request is queued */ if (!list_empty (&qh->qtd_list) @@ -889,7 +887,7 @@ static void ehci_free_config (struct usb ) { spin_unlock_irqrestore (&ehci->lock, flags); /* wait_ms() won't spin, we're a thread; - * and we know IRQ+tasklet can progress + * and we know IRQ can progress */ wait_ms (1); spin_lock_irqsave (&ehci->lock, flags); --- ./drivers/usb/host/ehci-sched.c.~1~ Mon Dec 9 14:11:16 2002 +++ ./drivers/usb/host/ehci-sched.c Mon Dec 9 14:19:13 2002 @@ -190,7 +190,7 @@ static int enable_periodic (struct ehci_ /* posted write ... PSS happens later */ ehci->hcd.state = USB_STATE_RUNNING; - /* make sure tasklet scans these */ + /* make sure ehci_work scans these */ ehci->next_uframe = readl (&ehci->regs->frame_index) % (ehci->periodic_size << 3); return 0; @@ -495,7 +495,8 @@ static unsigned intr_complete ( struct ehci_hcd *ehci, unsigned frame, - struct ehci_qh *qh + struct ehci_qh *qh, + struct pt_regs *regs ) { unsigned count; @@ -509,7 +510,7 @@ intr_complete ( } /* handle any completions */ - count = qh_completions (ehci, qh); + count = qh_completions (ehci, qh, regs); if (unlikely (list_empty (&qh->qtd_list))) intr_deschedule (ehci, qh, 0); @@ -867,7 +868,8 @@ static unsigned itd_complete ( struct ehci_hcd *ehci, struct ehci_itd *itd, - unsigned uframe + unsigned uframe, + struct pt_regs *regs ) { struct urb *urb = itd->urb; struct usb_iso_packet_descriptor *desc; @@ -922,7 +924,7 @@ itd_complete ( /* complete() can reenter this HCD */ spin_unlock (&ehci->lock); - usb_hcd_giveback_urb (&ehci->hcd, urb, NULL); + usb_hcd_giveback_urb (&ehci->hcd, urb, regs); spin_lock (&ehci->lock); /* defer stopping schedule; completion can submit */ @@ -973,7 +975,7 @@ static int itd_submit (struct ehci_hcd * /*-------------------------------------------------------------------------*/ static void -scan_periodic (struct ehci_hcd *ehci) +scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs) { unsigned frame, clock, now_uframe, mod; unsigned count = 0; @@ -1031,7 +1033,7 @@ restart: temp = q.qh->qh_next; type = Q_NEXT_TYPE (q.qh->hw_next); count += intr_complete (ehci, frame, - qh_get (q.qh)); + qh_get (q.qh), regs); qh_put (ehci, q.qh); q = temp; break; @@ -1064,7 +1066,7 @@ restart: /* might free q.itd ... */ count += itd_complete (ehci, - temp.itd, uf); + temp.itd, uf, regs); break; } } ------------------------------------------------------- This sf.net email is sponsored by:ThinkGeek Welcome to geek heaven. http://thinkgeek.com/sf _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel