Add patches to fix RHBZ #663186
This commit is contained in:
parent
80bd8b191d
commit
c6232b615c
|
@ -0,0 +1,95 @@
|
|||
From 1729d20333739e6cc23023e405fe8668f08117a2 Mon Sep 17 00:00:00 2001
|
||||
From: Alan Stern <stern@rowland.harvard.edu>
|
||||
Date: Tue, 17 May 2011 10:40:51 -0400
|
||||
Subject: [PATCH 1/2] EHCI: don't rescan interrupt QHs needlessly
|
||||
|
||||
This patch (as1466) speeds up processing of ehci-hcd's periodic list.
|
||||
The existing code will pointlessly rescan an interrupt endpoint queue
|
||||
each time it encounters the queue's QH in the periodic list, which can
|
||||
happen quite a few times if the endpoint's period is low. On some
|
||||
embedded systems, this useless overhead can waste so much time that
|
||||
the driver falls hopelessly behind and loses events.
|
||||
|
||||
The patch introduces a "periodic_stamp" variable, which gets
|
||||
incremented each time scan_periodic() runs and each time the scan
|
||||
advances to a new frame. If the corresponding stamp in an interrupt
|
||||
QH is equal to the current periodic_stamp, we assume the QH has
|
||||
already been scanned and skip over it. Otherwise we scan the QH as
|
||||
usual, and if none of its URBs have completed then we store the
|
||||
current periodic_stamp in the QH's stamp, preventing it from being
|
||||
scanned again.
|
||||
|
||||
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
drivers/usb/host/ehci-q.c | 1 +
|
||||
drivers/usb/host/ehci-sched.c | 14 ++++++++++----
|
||||
drivers/usb/host/ehci.h | 1 +
|
||||
3 files changed, 12 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
|
||||
index ed8db6a..0079610 100644
|
||||
--- a/drivers/usb/host/ehci-q.c
|
||||
+++ b/drivers/usb/host/ehci-q.c
|
||||
@@ -826,6 +826,7 @@ qh_make (
|
||||
is_input, 0,
|
||||
hb_mult(maxp) * max_packet(maxp)));
|
||||
qh->start = NO_FRAME;
|
||||
+ qh->stamp = ehci->periodic_stamp;
|
||||
|
||||
if (urb->dev->speed == USB_SPEED_HIGH) {
|
||||
qh->c_usecs = 0;
|
||||
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
|
||||
index a530856..9e54e85 100644
|
||||
--- a/drivers/usb/host/ehci-sched.c
|
||||
+++ b/drivers/usb/host/ehci-sched.c
|
||||
@@ -2351,6 +2351,7 @@ scan_periodic (struct ehci_hcd *ehci)
|
||||
}
|
||||
clock %= mod;
|
||||
clock_frame = clock >> 3;
|
||||
+ ++ehci->periodic_stamp;
|
||||
|
||||
for (;;) {
|
||||
union ehci_shadow q, *q_p;
|
||||
@@ -2379,10 +2380,14 @@ restart:
|
||||
temp.qh = qh_get (q.qh);
|
||||
type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
|
||||
q = q.qh->qh_next;
|
||||
- modified = qh_completions (ehci, temp.qh);
|
||||
- if (unlikely(list_empty(&temp.qh->qtd_list) ||
|
||||
- temp.qh->needs_rescan))
|
||||
- intr_deschedule (ehci, temp.qh);
|
||||
+ if (temp.qh->stamp != ehci->periodic_stamp) {
|
||||
+ modified = qh_completions(ehci, temp.qh);
|
||||
+ if (!modified)
|
||||
+ temp.qh->stamp = ehci->periodic_stamp;
|
||||
+ if (unlikely(list_empty(&temp.qh->qtd_list) ||
|
||||
+ temp.qh->needs_rescan))
|
||||
+ intr_deschedule(ehci, temp.qh);
|
||||
+ }
|
||||
qh_put (temp.qh);
|
||||
break;
|
||||
case Q_TYPE_FSTN:
|
||||
@@ -2515,6 +2520,7 @@ restart:
|
||||
if (ehci->clock_frame != clock_frame) {
|
||||
free_cached_lists(ehci);
|
||||
ehci->clock_frame = clock_frame;
|
||||
+ ++ehci->periodic_stamp;
|
||||
}
|
||||
} else {
|
||||
now_uframe++;
|
||||
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
|
||||
index c702e4b..c2c2f9d 100644
|
||||
--- a/drivers/usb/host/ehci.h
|
||||
+++ b/drivers/usb/host/ehci.h
|
||||
@@ -117,6 +117,7 @@ struct ehci_hcd { /* one per controller */
|
||||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
unsigned stamp;
|
||||
+ unsigned periodic_stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
ktime_t last_periodic_enable;
|
||||
--
|
||||
1.7.6
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
From e8b80056d07bc849777d032bc699a59cc28f9ddb Mon Sep 17 00:00:00 2001
|
||||
From: Alan Stern <stern@rowland.harvard.edu>
|
||||
Date: Tue, 5 Jul 2011 12:34:05 -0400
|
||||
Subject: [PATCH 2/2] USB: EHCI: go back to using the system clock for QH
|
||||
unlinks
|
||||
|
||||
This patch (as1477) fixes a problem affecting a few types of EHCI
|
||||
controller. Contrary to what one might expect, these controllers
|
||||
automatically stop their internal frame counter when no ports are
|
||||
enabled. Since ehci-hcd currently relies on the frame counter for
|
||||
determining when it should unlink QHs from the async schedule, those
|
||||
controllers run into trouble: The frame counter stops and the QHs
|
||||
never get unlinked.
|
||||
|
||||
Some systems have also experienced other problems traced back to
|
||||
commit b963801164618e25fbdc0cd452ce49c3628b46c8 (USB: ehci-hcd unlink
|
||||
speedups), which made the original switch from using the system clock
|
||||
to using the frame counter. It never became clear what the reason was
|
||||
for these problems, but evidently it is related to use of the frame
|
||||
counter.
|
||||
|
||||
To fix all these problems, this patch more or less reverts that commit
|
||||
and goes back to using the system clock. But this can't be done
|
||||
cleanly because other changes have since been made to the scan_async()
|
||||
subroutine. One of these changes involved the tricky logic that tries
|
||||
to avoid rescanning QHs that have already been seen when the scanning
|
||||
loop is restarted, which happens whenever an URB is given back.
|
||||
Switching back to clock-based unlinks would make this logic even more
|
||||
complicated.
|
||||
|
||||
Therefore the new code doesn't rescan the entire async list whenever a
|
||||
giveback occurs. Instead it rescans only the current QH and continues
|
||||
on from there. This requires the use of a separate pointer to keep
|
||||
track of the next QH to scan, since the current QH may be unlinked
|
||||
while the scanning is in progress. That new pointer must be global,
|
||||
so that it can be adjusted forward whenever the _next_ QH gets
|
||||
unlinked. (uhci-hcd uses this same trick.)
|
||||
|
||||
Simplification of the scanning loop removes a level of indentation,
|
||||
which accounts for the size of the patch. The amount of code changed
|
||||
is relatively small, and it isn't exactly a reversion of the
|
||||
b963801164 commit.
|
||||
|
||||
This fixes Bugzilla #32432.
|
||||
|
||||
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
|
||||
CC: <stable@kernel.org>
|
||||
Tested-by: Matej Kenda <matejken@gmail.com>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
|
||||
---
|
||||
drivers/usb/host/ehci-hcd.c | 8 ++---
|
||||
drivers/usb/host/ehci-q.c | 82 +++++++++++++++++++++----------------------
|
||||
drivers/usb/host/ehci.h | 3 +-
|
||||
3 files changed, 45 insertions(+), 48 deletions(-)
|
||||
|
||||
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
|
||||
index 761bbb3..8e5b995 100644
|
||||
--- a/drivers/usb/host/ehci-hcd.c
|
||||
+++ b/drivers/usb/host/ehci-hcd.c
|
||||
@@ -83,7 +83,8 @@ static const char hcd_name [] = "ehci_hcd";
|
||||
#define EHCI_IAA_MSECS 10 /* arbitrary */
|
||||
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
|
||||
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
|
||||
-#define EHCI_SHRINK_FRAMES 5 /* async qh unlink delay */
|
||||
+#define EHCI_SHRINK_JIFFIES (DIV_ROUND_UP(HZ, 200) + 1)
|
||||
+ /* 200-ms async qh unlink delay */
|
||||
|
||||
/* Initial IRQ latency: faster than hw default */
|
||||
static int log2_irq_thresh = 0; // 0 to 6
|
||||
@@ -138,10 +139,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
|
||||
break;
|
||||
/* case TIMER_ASYNC_SHRINK: */
|
||||
default:
|
||||
- /* add a jiffie since we synch against the
|
||||
- * 8 KHz uframe counter.
|
||||
- */
|
||||
- t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
|
||||
+ t = EHCI_SHRINK_JIFFIES;
|
||||
break;
|
||||
}
|
||||
mod_timer(&ehci->watchdog, t + jiffies);
|
||||
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
|
||||
index 0079610..a664203 100644
|
||||
--- a/drivers/usb/host/ehci-q.c
|
||||
+++ b/drivers/usb/host/ehci-q.c
|
||||
@@ -1226,6 +1226,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
||||
|
||||
prev->hw->hw_next = qh->hw->hw_next;
|
||||
prev->qh_next = qh->qh_next;
|
||||
+ if (ehci->qh_scan_next == qh)
|
||||
+ ehci->qh_scan_next = qh->qh_next.qh;
|
||||
wmb ();
|
||||
|
||||
/* If the controller isn't running, we don't have to wait for it */
|
||||
@@ -1251,53 +1253,49 @@ static void scan_async (struct ehci_hcd *ehci)
|
||||
struct ehci_qh *qh;
|
||||
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
|
||||
|
||||
- ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
|
||||
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
|
||||
-rescan:
|
||||
stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
|
||||
- qh = ehci->async->qh_next.qh;
|
||||
- if (likely (qh != NULL)) {
|
||||
- do {
|
||||
- /* clean any finished work for this qh */
|
||||
- if (!list_empty(&qh->qtd_list) && (stopped ||
|
||||
- qh->stamp != ehci->stamp)) {
|
||||
- int temp;
|
||||
-
|
||||
- /* unlinks could happen here; completion
|
||||
- * reporting drops the lock. rescan using
|
||||
- * the latest schedule, but don't rescan
|
||||
- * qhs we already finished (no looping)
|
||||
- * unless the controller is stopped.
|
||||
- */
|
||||
- qh = qh_get (qh);
|
||||
- qh->stamp = ehci->stamp;
|
||||
- temp = qh_completions (ehci, qh);
|
||||
- if (qh->needs_rescan)
|
||||
- unlink_async(ehci, qh);
|
||||
- qh_put (qh);
|
||||
- if (temp != 0) {
|
||||
- goto rescan;
|
||||
- }
|
||||
- }
|
||||
|
||||
- /* unlink idle entries, reducing DMA usage as well
|
||||
- * as HCD schedule-scanning costs. delay for any qh
|
||||
- * we just scanned, there's a not-unusual case that it
|
||||
- * doesn't stay idle for long.
|
||||
- * (plus, avoids some kind of re-activation race.)
|
||||
+ ehci->qh_scan_next = ehci->async->qh_next.qh;
|
||||
+ while (ehci->qh_scan_next) {
|
||||
+ qh = ehci->qh_scan_next;
|
||||
+ ehci->qh_scan_next = qh->qh_next.qh;
|
||||
+ rescan:
|
||||
+ /* clean any finished work for this qh */
|
||||
+ if (!list_empty(&qh->qtd_list)) {
|
||||
+ int temp;
|
||||
+
|
||||
+ /*
|
||||
+ * Unlinks could happen here; completion reporting
|
||||
+ * drops the lock. That's why ehci->qh_scan_next
|
||||
+ * always holds the next qh to scan; if the next qh
|
||||
+ * gets unlinked then ehci->qh_scan_next is adjusted
|
||||
+ * in start_unlink_async().
|
||||
*/
|
||||
- if (list_empty(&qh->qtd_list)
|
||||
- && qh->qh_state == QH_STATE_LINKED) {
|
||||
- if (!ehci->reclaim && (stopped ||
|
||||
- ((ehci->stamp - qh->stamp) & 0x1fff)
|
||||
- >= EHCI_SHRINK_FRAMES * 8))
|
||||
- start_unlink_async(ehci, qh);
|
||||
- else
|
||||
- action = TIMER_ASYNC_SHRINK;
|
||||
- }
|
||||
+ qh = qh_get(qh);
|
||||
+ temp = qh_completions(ehci, qh);
|
||||
+ if (qh->needs_rescan)
|
||||
+ unlink_async(ehci, qh);
|
||||
+ qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
|
||||
+ qh_put(qh);
|
||||
+ if (temp != 0)
|
||||
+ goto rescan;
|
||||
+ }
|
||||
|
||||
- qh = qh->qh_next.qh;
|
||||
- } while (qh);
|
||||
+ /* unlink idle entries, reducing DMA usage as well
|
||||
+ * as HCD schedule-scanning costs. delay for any qh
|
||||
+ * we just scanned, there's a not-unusual case that it
|
||||
+ * doesn't stay idle for long.
|
||||
+ * (plus, avoids some kind of re-activation race.)
|
||||
+ */
|
||||
+ if (list_empty(&qh->qtd_list)
|
||||
+ && qh->qh_state == QH_STATE_LINKED) {
|
||||
+ if (!ehci->reclaim && (stopped ||
|
||||
+ time_after_eq(jiffies, qh->unlink_time)))
|
||||
+ start_unlink_async(ehci, qh);
|
||||
+ else
|
||||
+ action = TIMER_ASYNC_SHRINK;
|
||||
+ }
|
||||
}
|
||||
if (action == TIMER_ASYNC_SHRINK)
|
||||
timer_action (ehci, TIMER_ASYNC_SHRINK);
|
||||
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
|
||||
index c2c2f9d..23d9a5e 100644
|
||||
--- a/drivers/usb/host/ehci.h
|
||||
+++ b/drivers/usb/host/ehci.h
|
||||
@@ -74,6 +74,7 @@ struct ehci_hcd { /* one per controller */
|
||||
/* async schedule support */
|
||||
struct ehci_qh *async;
|
||||
struct ehci_qh *reclaim;
|
||||
+ struct ehci_qh *qh_scan_next;
|
||||
unsigned scanning : 1;
|
||||
|
||||
/* periodic schedule support */
|
||||
@@ -116,7 +117,6 @@ struct ehci_hcd { /* one per controller */
|
||||
struct timer_list iaa_watchdog;
|
||||
struct timer_list watchdog;
|
||||
unsigned long actions;
|
||||
- unsigned stamp;
|
||||
unsigned periodic_stamp;
|
||||
unsigned random_frame;
|
||||
unsigned long next_statechange;
|
||||
@@ -337,6 +337,7 @@ struct ehci_qh {
|
||||
struct ehci_qh *reclaim; /* next to reclaim */
|
||||
|
||||
struct ehci_hcd *ehci;
|
||||
+ unsigned long unlink_time;
|
||||
|
||||
/*
|
||||
* Do NOT use atomic operations for QH refcounting. On some CPUs
|
||||
--
|
||||
1.7.6
|
||||
|
13
kernel.spec
13
kernel.spec
|
@ -48,7 +48,7 @@ Summary: The Linux kernel
|
|||
# reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec).
|
||||
# scripts/rebase.sh should be made to do that for you, actually.
|
||||
#
|
||||
%global baserelease 98
|
||||
%global baserelease 99
|
||||
%global fedora_build %{baserelease}
|
||||
|
||||
# base_sublevel is the kernel version we're starting with and patching
|
||||
|
@ -892,6 +892,10 @@ Patch14059: fuse-check-size-of-FUSE_NOTIFY_INVAL_ENTRY-message.patch
|
|||
Patch14060: TPM-Call-tpm_transmit-with-correct-size.patch
|
||||
Patch14061: TPM-Zero-buffer-after-copying-to-userspace.patch
|
||||
|
||||
# RHBZ #663186
|
||||
Patch14062: 0001-EHCI-don-t-rescan-interrupt-QHs-needlessly.patch
|
||||
Patch14063: 0002-USB-EHCI-go-back-to-using-the-system-clock-for-QH-un.patch
|
||||
|
||||
%endif
|
||||
|
||||
BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root
|
||||
|
@ -1687,6 +1691,10 @@ ApplyPatch fuse-check-size-of-FUSE_NOTIFY_INVAL_ENTRY-message.patch
|
|||
ApplyPatch TPM-Call-tpm_transmit-with-correct-size.patch
|
||||
ApplyPatch TPM-Zero-buffer-after-copying-to-userspace.patch
|
||||
|
||||
# RHBZ #663186
|
||||
ApplyPatch 0001-EHCI-don-t-rescan-interrupt-QHs-needlessly.patch
|
||||
ApplyPatch 0002-USB-EHCI-go-back-to-using-the-system-clock-for-QH-un.patch
|
||||
|
||||
# END OF PATCH APPLICATIONS
|
||||
|
||||
%endif
|
||||
|
@ -2273,6 +2281,9 @@ fi
|
|||
# and build.
|
||||
|
||||
%changelog
|
||||
* Fri Oct 14 2011 Josh Boyer <jwboyer@redhat.com>
|
||||
- Add patches to fix RHBZ #663186
|
||||
|
||||
* Tue Oct 11 2011 Dave Jones <davej@redhat.com>
|
||||
- acer-wmi: Fix capitalisation of GUID in module alias (rhbz 661322)
|
||||
|
||||
|
|
Loading…
Reference in New Issue