aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2011-10-12 10:39:14 -0400
committerHerton Ronaldo Krzesinski <herton.krzesinski@canonical.com>2011-11-21 12:54:51 -0500
commitfa3bb14b6324901650816a1be271780cb6a13e4a (patch)
tree2dcb0b556e938101930c91dde5a961ddc18949da /drivers/usb
parent2480f21170b5ad9a7857e71363c63efc8a3dcf4b (diff)
EHCI: workaround for MosChip controller bug
BugLink: http://bugs.launchpad.net/bugs/890952 commit 68aa95d5d4de31c9348c1628ffa85c805305ebc5 upstream. This patch (as1489) works around a hardware bug in MosChip EHCI controllers. Evidently when one of these controllers increments the frame-index register, it changes the three low-order bits (the microframe counter) before changing the higher order bits (the frame counter). If the register is read at just the wrong time, the value obtained is too low by 8. When the appropriate quirk flag is set, we work around this problem by reading the frame-index register a second time if the first value's three low-order bits are all 0. This gives the hardware a chance to finish updating the register, yielding the correct value. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Jason N Pitt <jpitt@fhcrc.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ehci-dbg.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c3
-rw-r--r--drivers/usb/host/ehci-pci.c5
-rw-r--r--drivers/usb/host/ehci-sched.c30
-rw-r--r--drivers/usb/host/ehci.h17
5 files changed, 49 insertions, 8 deletions
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 40a844c1dbb..3e2ccb0dd25 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -808,7 +808,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
808 next += temp; 808 next += temp;
809 809
810 temp = scnprintf (next, size, "uframe %04x\n", 810 temp = scnprintf (next, size, "uframe %04x\n",
811 ehci_readl(ehci, &ehci->regs->frame_index)); 811 ehci_read_frame_index(ehci));
812 size -= temp; 812 size -= temp;
813 next += temp; 813 next += temp;
814 814
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c45a116f50f..b27ceab1774 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1188,8 +1188,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
1188static int ehci_get_frame (struct usb_hcd *hcd) 1188static int ehci_get_frame (struct usb_hcd *hcd)
1189{ 1189{
1190 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 1190 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
1191 return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) % 1191 return (ehci_read_frame_index(ehci) >> 3) % ehci->periodic_size;
1192 ehci->periodic_size;
1193} 1192}
1194 1193
1195/*-------------------------------------------------------------------------*/ 1194/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 1102ce65a3a..1d1caa6a33f 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -224,6 +224,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
224 pci_dev_put(p_smbus); 224 pci_dev_put(p_smbus);
225 } 225 }
226 break; 226 break;
227 case PCI_VENDOR_ID_NETMOS:
228 /* MosChip frame-index-register bug */
229 ehci_info(ehci, "applying MosChip frame-index workaround\n");
230 ehci->frame_index_bug = 1;
231 break;
227 } 232 }
228 233
229 /* optional debug port, normally in the first BAR */ 234 /* optional debug port, normally in the first BAR */
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 6c9fbe352f7..063c630d246 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -36,6 +36,27 @@
36 36
37static int ehci_get_frame (struct usb_hcd *hcd); 37static int ehci_get_frame (struct usb_hcd *hcd);
38 38
39#ifdef CONFIG_PCI
40
41static unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
42{
43 unsigned uf;
44
45 /*
46 * The MosChip MCS9990 controller updates its microframe counter
47 * a little before the frame counter, and occasionally we will read
48 * the invalid intermediate value. Avoid problems by checking the
49 * microframe number (the low-order 3 bits); if they are 0 then
50 * re-read the register to get the correct value.
51 */
52 uf = ehci_readl(ehci, &ehci->regs->frame_index);
53 if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0)))
54 uf = ehci_readl(ehci, &ehci->regs->frame_index);
55 return uf;
56}
57
58#endif
59
39/*-------------------------------------------------------------------------*/ 60/*-------------------------------------------------------------------------*/
40 61
41/* 62/*
@@ -482,7 +503,7 @@ static int enable_periodic (struct ehci_hcd *ehci)
482 ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; 503 ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
483 504
484 /* make sure ehci_work scans these */ 505 /* make sure ehci_work scans these */
485 ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index) 506 ehci->next_uframe = ehci_read_frame_index(ehci)
486 % (ehci->periodic_size << 3); 507 % (ehci->periodic_size << 3);
487 if (unlikely(ehci->broken_periodic)) 508 if (unlikely(ehci->broken_periodic))
488 ehci->last_periodic_enable = ktime_get_real(); 509 ehci->last_periodic_enable = ktime_get_real();
@@ -1412,7 +1433,7 @@ iso_stream_schedule (
1412 goto fail; 1433 goto fail;
1413 } 1434 }
1414 1435
1415 now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1); 1436 now = ehci_read_frame_index(ehci) & (mod - 1);
1416 1437
1417 /* Typical case: reuse current schedule, stream is still active. 1438 /* Typical case: reuse current schedule, stream is still active.
1418 * Hopefully there are no gaps from the host falling behind 1439 * Hopefully there are no gaps from the host falling behind
@@ -2279,7 +2300,7 @@ scan_periodic (struct ehci_hcd *ehci)
2279 */ 2300 */
2280 now_uframe = ehci->next_uframe; 2301 now_uframe = ehci->next_uframe;
2281 if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { 2302 if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
2282 clock = ehci_readl(ehci, &ehci->regs->frame_index); 2303 clock = ehci_read_frame_index(ehci);
2283 clock_frame = (clock >> 3) & (ehci->periodic_size - 1); 2304 clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
2284 } else { 2305 } else {
2285 clock = now_uframe + mod - 1; 2306 clock = now_uframe + mod - 1;
@@ -2458,8 +2479,7 @@ restart:
2458 || ehci->periodic_sched == 0) 2479 || ehci->periodic_sched == 0)
2459 break; 2480 break;
2460 ehci->next_uframe = now_uframe; 2481 ehci->next_uframe = now_uframe;
2461 now = ehci_readl(ehci, &ehci->regs->frame_index) & 2482 now = ehci_read_frame_index(ehci) & (mod - 1);
2462 (mod - 1);
2463 if (now_uframe == now) 2483 if (now_uframe == now)
2464 break; 2484 break;
2465 2485
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 989e0a8e01f..3ffb27f472c 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -137,6 +137,7 @@ struct ehci_hcd { /* one per controller */
137 unsigned fs_i_thresh:1; /* Intel iso scheduling */ 137 unsigned fs_i_thresh:1; /* Intel iso scheduling */
138 unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ 138 unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
139 unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ 139 unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
140 unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
140 141
141 /* required for usb32 quirk */ 142 /* required for usb32 quirk */
142 #define OHCI_CTRL_HCFS (3 << 6) 143 #define OHCI_CTRL_HCFS (3 << 6)
@@ -738,6 +739,22 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
738 739
739/*-------------------------------------------------------------------------*/ 740/*-------------------------------------------------------------------------*/
740 741
742#ifdef CONFIG_PCI
743
744/* For working around the MosChip frame-index-register bug */
745static unsigned ehci_read_frame_index(struct ehci_hcd *ehci);
746
747#else
748
749static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
750{
751 return ehci_readl(ehci, &ehci->regs->frame_index);
752}
753
754#endif
755
756/*-------------------------------------------------------------------------*/
757
741#ifndef DEBUG 758#ifndef DEBUG
742#define STUB_DEBUG_FILES 759#define STUB_DEBUG_FILES
743#endif /* DEBUG */ 760#endif /* DEBUG */