ChangeSet 1.2181.4.47, 2005/03/21 22:36:57-08:00, [EMAIL PROTECTED] [PATCH] UHCI updates
This is the fifth of five updates to the uhci-hcd driver: Separate out the part of the driver responsible for scanning the schedule and doing delayed processing. Put it in a new routine which can be called as needed (such as when the controller is suspended) from several places in addition to the usual IRQ handler. Signed-off-by: Alan Stern <[EMAIL PROTECTED]> Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]> drivers/usb/host/uhci-hcd.c | 66 ++++---------------------------------------- drivers/usb/host/uhci-hcd.h | 5 ++- drivers/usb/host/uhci-q.c | 55 ++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 61 deletions(-) diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c --- a/drivers/usb/host/uhci-hcd.c 2005-03-30 13:35:30 -08:00 +++ b/drivers/usb/host/uhci-hcd.c 2005-03-30 13:35:30 -08:00 @@ -113,18 +113,9 @@ struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct urb_priv *up; unsigned long flags; - int called_uhci_finish_completion = 0; spin_lock_irqsave(&uhci->lock, flags); - uhci_get_current_frame_number(uhci); - - if (!list_empty(&uhci->urb_remove_list) && - uhci->frame_number + uhci->is_stopped != - uhci->urb_remove_age) { - uhci_remove_pending_urbps(uhci); - uhci_finish_completion(uhci, NULL); - called_uhci_finish_completion = 1; - } + uhci_scan_schedule(uhci, NULL); list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; @@ -138,10 +129,6 @@ spin_unlock(&u->lock); } - /* Wake up anyone waiting for an URB to complete */ - if (called_uhci_finish_completion) - wake_up_all(&uhci->waitqh); - /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { uhci->fsbrtimeout = 0; @@ -175,7 +162,6 @@ struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; unsigned short status; - struct urb_priv *urbp, *tmp; /* * Read the interrupt status, and write it back to clear the @@ -205,37 +191,9 @@ uhci->resume_detect = 1; spin_lock(&uhci->lock); - uhci_get_current_frame_number(uhci); - - if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) - uhci_free_pending_qhs(uhci); - if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) - uhci_free_pending_tds(uhci); - if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) - uhci_remove_pending_urbps(uhci); - - if (list_empty(&uhci->urb_remove_list) && - list_empty(&uhci->td_remove_list) && - list_empty(&uhci->qh_remove_list)) - uhci_clear_next_interrupt(uhci); - else - uhci_set_next_interrupt(uhci); - - /* Walk the list of pending URBs to see which ones completed - * (must be _safe because uhci_transfer_result() dequeues URBs) */ - list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) { - struct urb *urb = urbp->urb; - - /* Checks the status and does all of the magic necessary */ - uhci_transfer_result(uhci, urb); - } - uhci_finish_completion(uhci, regs); - + uhci_scan_schedule(uhci, regs); spin_unlock(&uhci->lock); - /* Wake up anyone waiting for an URB to complete */ - wake_up_all(&uhci->waitqh); - return IRQ_HANDLED; } @@ -273,6 +231,8 @@ /* FIXME: Wait for the controller to actually stop */ uhci_get_current_frame_number(uhci); uhci->is_stopped = UHCI_IS_STOPPED; + + uhci_scan_schedule(uhci, NULL); } static void wakeup_hc(struct uhci_hcd *uhci) @@ -746,26 +706,11 @@ struct uhci_hcd *uhci = hcd_to_uhci(hcd); del_timer_sync(&uhci->stall_timer); - - /* - * At this point, we're guaranteed that no new connects can be made - * to this bus since there are no more parents - */ - reset_hc(uhci); spin_lock_irq(&uhci->lock); - uhci_free_pending_qhs(uhci); - uhci_free_pending_tds(uhci); - uhci_remove_pending_urbps(uhci); - uhci_finish_completion(uhci, NULL); - - uhci_free_pending_qhs(uhci); - uhci_free_pending_tds(uhci); + uhci_scan_schedule(uhci, NULL); spin_unlock_irq(&uhci->lock); - - /* Wake up anyone waiting for an URB to complete */ - wake_up_all(&uhci->waitqh); release_uhci(uhci); } @@ -784,6 +729,7 @@ spin_unlock_irq(&uhci->lock); reset_hc(uhci); spin_lock_irq(&uhci->lock); + uhci_scan_schedule(uhci, NULL); } spin_unlock_irq(&uhci->lock); diff -Nru a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h --- a/drivers/usb/host/uhci-hcd.h 2005-03-30 13:35:30 -08:00 +++ b/drivers/usb/host/uhci-hcd.h 2005-03-30 13:35:30 -08:00 @@ -365,10 +365,13 @@ enum uhci_state state; /* FIXME: needs a spinlock */ unsigned long state_end; /* Time of next transition */ - int resume_detect; /* Need a Global Resume */ unsigned int frame_number; /* As of last check */ unsigned int is_stopped; #define UHCI_IS_STOPPED 9999 /* Larger than a frame # */ + + unsigned int scan_in_progress:1; /* Schedule scan is running */ + unsigned int need_rescan:1; /* Redo the schedule scan */ + unsigned int resume_detect:1; /* Need a Global Resume */ /* Support for port suspend/resume/reset */ unsigned long port_c_suspend; /* Bit-arrays of ports */ diff -Nru a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c --- a/drivers/usb/host/uhci-q.c 2005-03-30 13:35:30 -08:00 +++ b/drivers/usb/host/uhci-q.c 2005-03-30 13:35:30 -08:00 @@ -1482,3 +1482,58 @@ /* Splice the urb_remove_list onto the end of the complete_list */ list_splice_init(&uhci->urb_remove_list, uhci->complete_list.prev); } + +/* Process events in the schedule, but only in one thread at a time */ +static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs) +{ + struct urb_priv *urbp, *tmp; + + /* Don't allow re-entrant calls */ + if (uhci->scan_in_progress) { + uhci->need_rescan = 1; + return; + } + uhci->scan_in_progress = 1; + rescan: + uhci->need_rescan = 0; + + uhci_get_current_frame_number(uhci); + + if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age) + uhci_free_pending_qhs(uhci); + if (uhci->frame_number + uhci->is_stopped != uhci->td_remove_age) + uhci_free_pending_tds(uhci); + if (uhci->frame_number + uhci->is_stopped != uhci->urb_remove_age) + uhci_remove_pending_urbps(uhci); + + /* Walk the list of pending URBs to see which ones completed + * (must be _safe because uhci_transfer_result() dequeues URBs) */ + list_for_each_entry_safe(urbp, tmp, &uhci->urb_list, urb_list) { + struct urb *urb = urbp->urb; + + /* Checks the status and does all of the magic necessary */ + uhci_transfer_result(uhci, urb); + } + uhci_finish_completion(uhci, regs); + + /* If the controller is stopped, we can finish these off right now */ + if (uhci->is_stopped) { + uhci_free_pending_qhs(uhci); + uhci_free_pending_tds(uhci); + uhci_remove_pending_urbps(uhci); + } + + if (uhci->need_rescan) + goto rescan; + uhci->scan_in_progress = 0; + + if (list_empty(&uhci->urb_remove_list) && + list_empty(&uhci->td_remove_list) && + list_empty(&uhci->qh_remove_list)) + uhci_clear_next_interrupt(uhci); + else + uhci_set_next_interrupt(uhci); + + /* Wake up anyone waiting for an URB to complete */ + wake_up_all(&uhci->waitqh); +} ------------------------------------------------------- This SF.net email is sponsored by Demarc: A global provider of Threat Management Solutions. Download our HomeAdmin security software for free today! http://www.demarc.com/info/Sentarus/hamr30 _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel