From d58b4bcc6df8046cf9c3c59f9ff84d2cd86b93eb Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:21:54 -0400 Subject: USB: EHCI: introduce high-res timer This patch (as1572) begins the conversion of ehci-hcd over to using high-resolution timers rather than old-fashioned low-resolution kernel timers. This reduces overhead caused by timer roundoff on systems where HZ is smaller than 1000. Also, the new timer framework introduced here is much more logical and easily extended than the ad-hoc approach ehci-hcd currently uses for timers. An hrtimer structure is added to ehci_hcd, along with a bitflag array and an array of ktime_t values, to keep track of which timing events are pending and what their expiration times are. Only the infrastructure for the timing operations is added in this patch. Later patches will add routines for handling each of the various timing events the driver needs. In some cases the new hrtimer handlers will replace the existing handlers for ehci-hcd's kernel timers; as this happens the old timers will be removed. In other cases the new timing events will replace busy-wait loops. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 106 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 drivers/usb/host/ehci-timer.c (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c new file mode 100644 index 000000000000..f6279e2883a8 --- /dev/null +++ b/drivers/usb/host/ehci-timer.c @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2012 by Alan Stern + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* This file is part of ehci-hcd.c */ + +/*-------------------------------------------------------------------------*/ + +/* + * EHCI timer support... Now using hrtimers. + * + * Lots of different events are triggered from ehci->hrtimer. Whenever + * the timer routine runs, it checks each possible event; events that are + * currently enabled and whose expiration time has passed get handled. + * The set of enabled events is stored as a collection of bitflags in + * ehci->enabled_hrtimer_events, and they are numbered in order of + * increasing delay values (ranging between 1 ms and 100 ms). + * + * Rather than implementing a sorted list or tree of all pending events, + * we keep track only of the lowest-numbered pending event, in + * ehci->next_hrtimer_event. Whenever ehci->hrtimer gets restarted, its + * expiration time is set to the timeout value for this event. + * + * As a result, events might not get handled right away; the actual delay + * could be anywhere up to twice the requested delay. This doesn't + * matter, because none of the events are especially time-critical. The + * ones that matter most all have a delay of 1 ms, so they will be + * handled after 2 ms at most, which is okay. In addition to this, we + * allow for an expiration range of 1 ms. + */ + +/* + * Delay lengths for the hrtimer event types. + * Keep this list sorted by delay length, in the same order as + * the event types indexed by enum ehci_hrtimer_event in ehci.h. + */ +static unsigned event_delays_ns[] = { +}; + +/* Enable a pending hrtimer event */ +static void ehci_enable_event(struct ehci_hcd *ehci, unsigned event, + bool resched) +{ + ktime_t *timeout = &ehci->hr_timeouts[event]; + + if (resched) + *timeout = ktime_add(ktime_get(), + ktime_set(0, event_delays_ns[event])); + ehci->enabled_hrtimer_events |= (1 << event); + + /* Track only the lowest-numbered pending event */ + if (event < ehci->next_hrtimer_event) { + ehci->next_hrtimer_event = event; + hrtimer_start_range_ns(&ehci->hrtimer, *timeout, + NSEC_PER_MSEC, HRTIMER_MODE_ABS); + } +} + + +/* + * Handler functions for the hrtimer event types. + * Keep this array in the same order as the event types indexed by + * enum ehci_hrtimer_event in ehci.h. + */ +static void (*event_handlers[])(struct ehci_hcd *) = { +}; + +static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) +{ + struct ehci_hcd *ehci = container_of(t, struct ehci_hcd, hrtimer); + ktime_t now; + unsigned long events; + unsigned long flags; + unsigned e; + + spin_lock_irqsave(&ehci->lock, flags); + + events = ehci->enabled_hrtimer_events; + ehci->enabled_hrtimer_events = 0; + ehci->next_hrtimer_event = EHCI_HRTIMER_NO_EVENT; + + /* + * Check each pending event. If its time has expired, handle + * the event; otherwise re-enable it. + */ + now = ktime_get(); + for_each_set_bit(e, &events, EHCI_HRTIMER_NUM_EVENTS) { + if (now.tv64 >= ehci->hr_timeouts[e].tv64) + event_handlers[e](ehci); + else + ehci_enable_event(ehci, e, false); + } + + spin_unlock_irqrestore(&ehci->lock, flags); + return HRTIMER_NORESTART; +} -- cgit v1.2.2 From 3ca9aebac2ebb8f56d2d097636b8c568320a9f87 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:22:05 -0400 Subject: USB: EHCI: use hrtimer for the periodic schedule This patch (as1573) adds hrtimer support for managing ehci-hcd's periodic schedule. There are two issues to deal with. First, the schedule's state (on or off) must not be changed until the hardware status has caught up with the current command. This is handled by an hrtimer event that polls at 1-ms intervals to see when the Periodic Schedule Status (PSS) flag matches the Periodic Schedule Enable (PSE) value. Second, the schedule should not be turned off as soon as it becomes empty. Turning the schedule on and off takes time, so we want to wait until the schedule has been empty for a suitable period before turning it off. This is handled by an hrtimer event that gets set to expire 10 ms after the periodic schedule becomes empty. The existing code polls (for up to 1125 us and with interrupts disabled!) to check the status, and doesn't implement a delay before turning off the schedule. Furthermore, if the polling fails then the driver decides that the controller has died. This has caused problems for several people; some controllers can take 10 ms or more to turn off their periodic schedules. This patch fixes these issues. It also makes the "broken_periodic" workaround unnecessary; there is no longer any danger of turning off the periodic schedule after it has been on for less than 1 ms. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 80 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index f6279e2883a8..ecd3296157c6 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -16,6 +16,28 @@ /*-------------------------------------------------------------------------*/ +/* Set a bit in the USBCMD register */ +static void ehci_set_command_bit(struct ehci_hcd *ehci, u32 bit) +{ + ehci->command |= bit; + ehci_writel(ehci, ehci->command, &ehci->regs->command); + + /* unblock posted write */ + ehci_readl(ehci, &ehci->regs->command); +} + +/* Clear a bit in the USBCMD register */ +static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit) +{ + ehci->command &= ~bit; + ehci_writel(ehci, ehci->command, &ehci->regs->command); + + /* unblock posted write */ + ehci_readl(ehci, &ehci->regs->command); +} + +/*-------------------------------------------------------------------------*/ + /* * EHCI timer support... Now using hrtimers. * @@ -45,6 +67,8 @@ * the event types indexed by enum ehci_hrtimer_event in ehci.h. */ static unsigned event_delays_ns[] = { + 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */ + 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ }; /* Enable a pending hrtimer event */ @@ -67,12 +91,68 @@ static void ehci_enable_event(struct ehci_hcd *ehci, unsigned event, } +/* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */ +static void ehci_poll_PSS(struct ehci_hcd *ehci) +{ + unsigned actual, want; + + /* Don't do anything if the controller isn't running (e.g., died) */ + if (ehci->rh_state != EHCI_RH_RUNNING) + return; + + want = (ehci->command & CMD_PSE) ? STS_PSS : 0; + actual = ehci_readl(ehci, &ehci->regs->status) & STS_PSS; + + if (want != actual) { + + /* Poll again later, but give up after about 20 ms */ + if (ehci->PSS_poll_count++ < 20) { + ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); + return; + } + ehci_warn(ehci, "Waited too long for the periodic schedule status, giving up\n"); + } + ehci->PSS_poll_count = 0; + + /* The status is up-to-date; restart or stop the schedule as needed */ + if (want == 0) { /* Stopped */ + free_cached_lists(ehci); + if (ehci->periodic_count > 0) { + + /* make sure ehci_work scans these */ + ehci->next_uframe = ehci_read_frame_index(ehci) + & ((ehci->periodic_size << 3) - 1); + ehci_set_command_bit(ehci, CMD_PSE); + } + + } else { /* Running */ + if (ehci->periodic_count == 0) { + + /* Turn off the schedule after a while */ + ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_PERIODIC, + true); + } + } +} + +/* Turn off the periodic schedule after a brief delay */ +static void ehci_disable_PSE(struct ehci_hcd *ehci) +{ + ehci_clear_command_bit(ehci, CMD_PSE); + + /* Poll to see when it actually stops */ + ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); +} + + /* * Handler functions for the hrtimer event types. * Keep this array in the same order as the event types indexed by * enum ehci_hrtimer_event in ehci.h. */ static void (*event_handlers[])(struct ehci_hcd *) = { + ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */ + ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ }; static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) -- cgit v1.2.2 From 314466101c6ae14f6f5db8a86eda1509ba2c02a8 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:22:21 -0400 Subject: USB: EHCI: use hrtimer for async schedule This patch (as1576) adds hrtimer support for managing ehci-hcd's async schedule. Just as with the earlier change to the periodic schedule management, two new hrtimer events take care of everything. One event polls at 1-ms intervals to see when the Asynchronous Schedule Status (ASS) flag matches the Asynchronous Schedule Enable (ASE) value; the schedule's state must not be changed until it does. The other event delays for 15 ms after the async schedule becomes empty before turning it off. The new events replace a busy-wait poll and a kernel timer usage. They also replace the rather illogical method currently used for indicating the async schedule should be turned off: attempting to unlink the dedicated QH at the head of the async list. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index ecd3296157c6..1e907dd3bb1b 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -67,8 +67,10 @@ static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit) * the event types indexed by enum ehci_hrtimer_event in ehci.h. */ static unsigned event_delays_ns[] = { + 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_ASS */ 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ + 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ }; /* Enable a pending hrtimer event */ @@ -91,6 +93,51 @@ static void ehci_enable_event(struct ehci_hcd *ehci, unsigned event, } +/* Poll the STS_ASS status bit; see when it agrees with CMD_ASE */ +static void ehci_poll_ASS(struct ehci_hcd *ehci) +{ + unsigned actual, want; + + /* Don't enable anything if the controller isn't running (e.g., died) */ + if (ehci->rh_state != EHCI_RH_RUNNING) + return; + + want = (ehci->command & CMD_ASE) ? STS_ASS : 0; + actual = ehci_readl(ehci, &ehci->regs->status) & STS_ASS; + + if (want != actual) { + + /* Poll again later, but give up after about 20 ms */ + if (ehci->ASS_poll_count++ < 20) { + ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true); + return; + } + ehci_warn(ehci, "Waited too long for the async schedule status, giving up\n"); + } + ehci->ASS_poll_count = 0; + + /* The status is up-to-date; restart or stop the schedule as needed */ + if (want == 0) { /* Stopped */ + if (ehci->async_count > 0) + ehci_set_command_bit(ehci, CMD_ASE); + + } else { /* Running */ + if (ehci->async_count == 0) { + + /* Turn off the schedule after a while */ + ehci_enable_event(ehci, EHCI_HRTIMER_DISABLE_ASYNC, + true); + } + } +} + +/* Turn off the async schedule after a brief delay */ +static void ehci_disable_ASE(struct ehci_hcd *ehci) +{ + ehci_clear_command_bit(ehci, CMD_ASE); +} + + /* Poll the STS_PSS status bit; see when it agrees with CMD_PSE */ static void ehci_poll_PSS(struct ehci_hcd *ehci) { @@ -151,8 +198,10 @@ static void ehci_disable_PSE(struct ehci_hcd *ehci) * enum ehci_hrtimer_event in ehci.h. */ static void (*event_handlers[])(struct ehci_hcd *) = { + ehci_poll_ASS, /* EHCI_HRTIMER_POLL_ASS */ ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ + ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ }; static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) -- cgit v1.2.2 From df2022553dd8d34d49e16c19d851ea619438f0ef Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:22:26 -0400 Subject: USB: EHCI: use hrtimer for interrupt QH unlink This patch (as1577) adds hrtimer support for unlinking interrupt QHs in ehci-hcd. The current code relies on a fixed delay of either 2 or 55 us, which is not always adequate and in any case is totally bogus. Thanks to internal caching, the EHCI hardware may continue to access an interrupt QH for more than a millisecond after it has been unlinked. In fact, the EHCI spec doesn't say how long to wait before using an unlinked interrupt QH. The patch sets the delay to 9 microframes minimum, which ought to be adequate. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 1e907dd3bb1b..bd8b591771b0 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -69,6 +69,7 @@ static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit) static unsigned event_delays_ns[] = { 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_ASS */ 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */ + 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ }; @@ -192,6 +193,38 @@ static void ehci_disable_PSE(struct ehci_hcd *ehci) } +/* Handle unlinked interrupt QHs once they are gone from the hardware */ +static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) +{ + bool stopped = (ehci->rh_state < EHCI_RH_RUNNING); + + /* + * Process all the QHs on the intr_unlink list that were added + * before the current unlink cycle began. The list is in + * temporal order, so stop when we reach the first entry in the + * current cycle. But if the root hub isn't running then + * process all the QHs on the list. + */ + ehci->intr_unlinking = true; + while (ehci->intr_unlink) { + struct ehci_qh *qh = ehci->intr_unlink; + + if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle) + break; + ehci->intr_unlink = qh->unlink_next; + qh->unlink_next = NULL; + end_unlink_intr(ehci, qh); + } + + /* Handle remaining entries later */ + if (ehci->intr_unlink) { + ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true); + ++ehci->intr_unlink_cycle; + } + ehci->intr_unlinking = false; +} + + /* * Handler functions for the hrtimer event types. * Keep this array in the same order as the event types indexed by @@ -200,6 +233,7 @@ static void ehci_disable_PSE(struct ehci_hcd *ehci) static void (*event_handlers[])(struct ehci_hcd *) = { ehci_poll_ASS, /* EHCI_HRTIMER_POLL_ASS */ ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */ + ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ }; -- cgit v1.2.2 From bf6387bcd16975ba8952b094f262a359d74e1c8a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:22:31 -0400 Subject: USB: EHCI: use hrtimer for controller death This patch (as1578) adds an hrtimer event to handle the death of an EHCI controller. When a controller dies, it doesn't necessarily stop running right away. The new event polls at 1-ms intervals to see when all activity has safely stopped. This replaces a busy-wait polling loop in the current code. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index bd8b591771b0..0c5326a8883c 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -69,6 +69,7 @@ static void ehci_clear_command_bit(struct ehci_hcd *ehci, u32 bit) static unsigned event_delays_ns[] = { 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_ASS */ 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */ + 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ @@ -193,6 +194,30 @@ static void ehci_disable_PSE(struct ehci_hcd *ehci) } +/* Poll the STS_HALT status bit; see when a dead controller stops */ +static void ehci_handle_controller_death(struct ehci_hcd *ehci) +{ + if (!(ehci_readl(ehci, &ehci->regs->status) & STS_HALT)) { + + /* Give up after a few milliseconds */ + if (ehci->died_poll_count++ < 5) { + /* Try again later */ + ehci_enable_event(ehci, EHCI_HRTIMER_POLL_DEAD, true); + return; + } + ehci_warn(ehci, "Waited too long for the controller to stop, giving up\n"); + } + + /* Clean up the mess */ + ehci->rh_state = EHCI_RH_HALTED; + ehci_writel(ehci, 0, &ehci->regs->configured_flag); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + ehci_work(ehci); + + /* Not in process context, so don't try to reset the controller */ +} + + /* Handle unlinked interrupt QHs once they are gone from the hardware */ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) { @@ -233,6 +258,7 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) static void (*event_handlers[])(struct ehci_hcd *) = { ehci_poll_ASS, /* EHCI_HRTIMER_POLL_ASS */ ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */ + ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ -- cgit v1.2.2 From 55934eb3b9fa52eb53b9d7342267fc73c38206aa Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:22:35 -0400 Subject: USB: EHCI: use hrtimer for (s)iTD deallocation This patch (as1579) adds an hrtimer event to handle deallocation of iTDs and siTDs in ehci-hcd. Because of the frame-oriented approach used by the EHCI periodic schedule, the hardware can continue to access the Transfer Descriptor for isochronous (or split-isochronous) transactions for up to a millisecond after the transaction completes. The iTD (or siTD) must not be reused before then. The strategy currently used involves putting completed iTDs on a list of cached entries and every so often returning them to the endpoint's free list. The new strategy reduces overhead by putting completed iTDs back on the free list immediately, although they are not reused until it is safe to do so. When the isochronous endpoint stops (its queue becomes empty), the iTDs on its free list get moved to a global list, from which they will be deallocated after a minimum of 2 ms. This delay is what the new hrtimer event is for. Overall this may not be a tremendous improvement over the current code, but to me it seems a lot more clear and logical. In addition, it removes the need for each iTD to keep a reference to the ehci_iso_stream it belongs to, since the iTD never needs to be moved back to the stream's free list from the global list. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 50 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 0c5326a8883c..8feb60ff4228 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -71,6 +71,7 @@ static unsigned event_delays_ns[] = { 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */ 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ + 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ }; @@ -165,7 +166,6 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci) /* The status is up-to-date; restart or stop the schedule as needed */ if (want == 0) { /* Stopped */ - free_cached_lists(ehci); if (ehci->periodic_count > 0) { /* make sure ehci_work scans these */ @@ -188,9 +188,6 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci) static void ehci_disable_PSE(struct ehci_hcd *ehci) { ehci_clear_command_bit(ehci, CMD_PSE); - - /* Poll to see when it actually stops */ - ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true); } @@ -250,6 +247,50 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci) } +/* Start another free-iTDs/siTDs cycle */ +static void start_free_itds(struct ehci_hcd *ehci) +{ + if (!(ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_FREE_ITDS))) { + ehci->last_itd_to_free = list_entry( + ehci->cached_itd_list.prev, + struct ehci_itd, itd_list); + ehci->last_sitd_to_free = list_entry( + ehci->cached_sitd_list.prev, + struct ehci_sitd, sitd_list); + ehci_enable_event(ehci, EHCI_HRTIMER_FREE_ITDS, true); + } +} + +/* Wait for controller to stop using old iTDs and siTDs */ +static void end_free_itds(struct ehci_hcd *ehci) +{ + struct ehci_itd *itd, *n; + struct ehci_sitd *sitd, *sn; + + if (ehci->rh_state < EHCI_RH_RUNNING) { + ehci->last_itd_to_free = NULL; + ehci->last_sitd_to_free = NULL; + } + + list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) { + list_del(&itd->itd_list); + dma_pool_free(ehci->itd_pool, itd, itd->itd_dma); + if (itd == ehci->last_itd_to_free) + break; + } + list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) { + list_del(&sitd->sitd_list); + dma_pool_free(ehci->sitd_pool, sitd, sitd->sitd_dma); + if (sitd == ehci->last_sitd_to_free) + break; + } + + if (!list_empty(&ehci->cached_itd_list) || + !list_empty(&ehci->cached_sitd_list)) + start_free_itds(ehci); +} + + /* * Handler functions for the hrtimer event types. * Keep this array in the same order as the event types indexed by @@ -260,6 +301,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */ ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ + end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ }; -- cgit v1.2.2 From 9d9387475af261949f61a5ec465e1f762d7be08a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:22:44 -0400 Subject: USB: EHCI: use hrtimer for the IAA watchdog This patch (as1581) replaces the iaa_watchdog kernel timer used by ehci-hcd with an hrtimer event, in keeping with the general conversion to high-res timers. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 8feb60ff4228..aab042064226 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = { 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ + 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ }; @@ -291,6 +292,49 @@ static void end_free_itds(struct ehci_hcd *ehci) } +/* Handle lost (or very late) IAA interrupts */ +static void ehci_iaa_watchdog(struct ehci_hcd *ehci) +{ + if (ehci->rh_state != EHCI_RH_RUNNING) + return; + + /* + * Lost IAA irqs wedge things badly; seen first with a vt8235. + * So we need this watchdog, but must protect it against both + * (a) SMP races against real IAA firing and retriggering, and + * (b) clean HC shutdown, when IAA watchdog was pending. + */ + if (ehci->async_unlink) { + u32 cmd, status; + + /* If we get here, IAA is *REALLY* late. It's barely + * conceivable that the system is so busy that CMD_IAAD + * is still legitimately set, so let's be sure it's + * clear before we read STS_IAA. (The HC should clear + * CMD_IAAD when it sets STS_IAA.) + */ + cmd = ehci_readl(ehci, &ehci->regs->command); + + /* + * If IAA is set here it either legitimately triggered + * after the watchdog timer expired (_way_ late, so we'll + * still count it as lost) ... or a silicon erratum: + * - VIA seems to set IAA without triggering the IRQ; + * - IAAD potentially cleared without setting IAA. + */ + status = ehci_readl(ehci, &ehci->regs->status); + if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { + COUNT(ehci->stats.lost_iaa); + ehci_writel(ehci, STS_IAA, &ehci->regs->status); + } + + ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", + status, cmd); + end_unlink_async(ehci); + } +} + + /* * Handler functions for the hrtimer event types. * Keep this array in the same order as the event types indexed by @@ -302,6 +346,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ + ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ }; -- cgit v1.2.2 From 3c273a056bf46167f0a1309c2ba72282a17d2541 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:22:49 -0400 Subject: USB: EHCI: unlink multiple async QHs together This patch (as1582) changes ehci-hcd's strategy for unlinking async QHs. Currently the driver never unlinks more than one QH at a time. This can be inefficient and cause unnecessary delays, since a QH cannot be reused while it is waiting to be unlinked. The new strategy unlinks all the waiting QHs at once. In practice the improvement won't be very big, because it's somewhat uncommon to have two or more QHs waiting to be unlinked at any time. But it does happen, and in any case, doing things this way makes more sense IMO. The change requires the async unlinking code to be refactored slightly. Now in addition to the routines for starting and ending an unlink, there are new routines for unlinking a single QH and starting an IAA cycle. This approach is needed because there are two separate paths for unlinking async QHs: When a transfer error occurs or an URB is cancelled, the QH must be unlinked right away; When a QH has been idle sufficiently long, it is unlinked to avoid consuming DMA bandwidth uselessly. In the first case we want the unlink to proceed as quickly as possible, whereas in the second case we can afford to batch several QHs together and unlink them all at once. Hence the division of labor. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index aab042064226..8ca5f152f5bd 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -211,6 +211,7 @@ static void ehci_handle_controller_death(struct ehci_hcd *ehci) ehci_writel(ehci, 0, &ehci->regs->configured_flag); ehci_writel(ehci, 0, &ehci->regs->intr_enable); ehci_work(ehci); + end_unlink_async(ehci); /* Not in process context, so don't try to reset the controller */ } @@ -304,7 +305,7 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci) * (a) SMP races against real IAA firing and retriggering, and * (b) clean HC shutdown, when IAA watchdog was pending. */ - if (ehci->async_unlink) { + if (ehci->async_iaa) { u32 cmd, status; /* If we get here, IAA is *REALLY* late. It's barely -- cgit v1.2.2 From 32830f207691176234b4c4dd17f0d7ab6d87d94b Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:22:53 -0400 Subject: USB: EHCI: use hrtimer for unlinking empty async QHs This patch (as1583) changes ehci-hcd to use an hrtimer event for unlinking empty (unused) async QHs instead of using a kernel timer. The check for empty QHs is moved to a new routine, where it doesn't require going through an entire scan of both the async and periodic schedules. And it can unlink multiple QHs at once, unlike the current code. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 8ca5f152f5bd..a823290b5139 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -72,6 +72,7 @@ static unsigned event_delays_ns[] = { 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */ + 6 * NSEC_PER_MSEC, /* EHCI_HRTIMER_ASYNC_UNLINKS */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ @@ -347,6 +348,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */ + unlink_empty_async, /* EHCI_HRTIMER_ASYNC_UNLINKS */ ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ -- cgit v1.2.2 From 569b394f53f0abd177cc665c9b4ace89e3f4c7fb Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:23:00 -0400 Subject: USB: EHCI: always scan each interrupt QH This patch (as1585) fixes a bug in ehci-hcd's scheme for scanning interrupt QHs. Currently a single routine takes care of scanning everything on the periodic schedule. Whenever an interrupt occurs, it scans all isochronous and interrupt URBs scheduled for frames that have elapsed since the last scan. This has two disadvantages. The first is relatively minor: An interrupt QH is likely to end up getting scanned multiple times, particularly if the last scan was not fairly recent. (The current code avoids this by maintaining a periodic_stamp in each interrupt QH.) The second is more serious. The periodic schedule wraps around. If the last scan occurred during frame N, and the next scan occurs when the schedule has gone through an entire cycle and is back at frame N, the scanning code won't look at any frames other than N. Consequently it won't see any QHs that completed during frame N-1 or earlier. The patch replaces the entire frame-based approach for scanning interrupt QHs with a new routine using a list-based approach, the same as for async QHs. This has a slight disadvantage, because it means that all interrupt QHs have to be scanned every time. But it is more robust than the current approach. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index a823290b5139..0e28bae78d18 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -168,13 +168,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci) /* The status is up-to-date; restart or stop the schedule as needed */ if (want == 0) { /* Stopped */ - if (ehci->periodic_count > 0) { - - /* make sure ehci_work scans these */ - ehci->next_uframe = ehci_read_frame_index(ehci) - & ((ehci->periodic_size << 3) - 1); + if (ehci->periodic_count > 0) ehci_set_command_bit(ehci, CMD_PSE); - } } else { /* Running */ if (ehci->periodic_count == 0) { -- cgit v1.2.2 From 18aafe64d75d0e27dae206cacf4171e4e485d285 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 11 Jul 2012 11:23:04 -0400 Subject: USB: EHCI: use hrtimer for the I/O watchdog This patch (as1586) replaces the kernel timer used by ehci-hcd as an I/O watchdog with an hrtimer event. Unlike in the current code, the watchdog event is now always enabled whenever any isochronous URBs are active. This will prevent bugs caused by the periodic schedule wrapping around with no completion interrupts; the watchdog handler is guaranteed to scan the isochronous transfers at least once during each iteration of the schedule. The extra overhead will be negligible: one timer interrupt every 100 ms. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-timer.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/usb/host/ehci-timer.c') diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 0e28bae78d18..eb896a2c8f2e 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -76,6 +76,7 @@ static unsigned event_delays_ns[] = { 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IAA_WATCHDOG */ 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ + 100 * NSEC_PER_MSEC, /* EHCI_HRTIMER_IO_WATCHDOG */ }; /* Enable a pending hrtimer event */ @@ -332,6 +333,25 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci) } +/* Enable the I/O watchdog, if appropriate */ +static void turn_on_io_watchdog(struct ehci_hcd *ehci) +{ + /* Not needed if the controller isn't running or it's already enabled */ + if (ehci->rh_state != EHCI_RH_RUNNING || + (ehci->enabled_hrtimer_events & + BIT(EHCI_HRTIMER_IO_WATCHDOG))) + return; + + /* + * Isochronous transfers always need the watchdog. + * For other sorts we use it only if the flag is set. + */ + if (ehci->isoc_count > 0 || (ehci->need_io_watchdog && + ehci->async_count + ehci->intr_count > 0)) + ehci_enable_event(ehci, EHCI_HRTIMER_IO_WATCHDOG, true); +} + + /* * Handler functions for the hrtimer event types. * Keep this array in the same order as the event types indexed by @@ -347,6 +367,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = { ehci_iaa_watchdog, /* EHCI_HRTIMER_IAA_WATCHDOG */ ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ + ehci_work, /* EHCI_HRTIMER_IO_WATCHDOG */ }; static enum hrtimer_restart ehci_hrtimer_func(struct hrtimer *t) -- cgit v1.2.2