aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/uhci-debug.c4
-rw-r--r--drivers/usb/host/uhci-hcd.c40
-rw-r--r--drivers/usb/host/uhci-hcd.h3
3 files changed, 28 insertions, 19 deletions
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 081c592fe8b1..ecef5880cfd9 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -289,7 +289,7 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
289 unsigned short portsc1, portsc2; 289 unsigned short portsc1, portsc2;
290 290
291 /* Try to make sure there's enough memory */ 291 /* Try to make sure there's enough memory */
292 if (len < 80 * 6) 292 if (len < 80 * 9)
293 return 0; 293 return 0;
294 294
295 usbcmd = inw(io_addr + 0); 295 usbcmd = inw(io_addr + 0);
@@ -328,6 +328,8 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
328 out += sprintf(out, " sof = %02x\n", sof); 328 out += sprintf(out, " sof = %02x\n", sof);
329 out += uhci_show_sc(1, portsc1, out, len - (out - buf)); 329 out += uhci_show_sc(1, portsc1, out, len - (out - buf));
330 out += uhci_show_sc(2, portsc2, out, len - (out - buf)); 330 out += uhci_show_sc(2, portsc2, out, len - (out - buf));
331 out += sprintf(out, "Most recent frame: %x\n",
332 uhci->frame_number);
331 333
332 return out - buf; 334 return out - buf;
333} 335}
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 395402eec5ef..5e75ad6dc29f 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -13,7 +13,7 @@
13 * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface 13 * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
14 * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). 14 * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
15 * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) 15 * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
16 * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu 16 * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
17 * 17 *
18 * Intel documents this fairly well, and as far as I know there 18 * Intel documents this fairly well, and as far as I know there
19 * are no royalties or anything like that, but even so there are 19 * are no royalties or anything like that, but even so there are
@@ -31,7 +31,6 @@
31#include <linux/ioport.h> 31#include <linux/ioport.h>
32#include <linux/sched.h> 32#include <linux/sched.h>
33#include <linux/slab.h> 33#include <linux/slab.h>
34#include <linux/smp_lock.h>
35#include <linux/errno.h> 34#include <linux/errno.h>
36#include <linux/unistd.h> 35#include <linux/unistd.h>
37#include <linux/interrupt.h> 36#include <linux/interrupt.h>
@@ -146,7 +145,8 @@ static void configure_hc(struct uhci_hcd *uhci)
146 outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD); 145 outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
147 146
148 /* Set the current frame number */ 147 /* Set the current frame number */
149 outw(uhci->frame_number, uhci->io_addr + USBFRNUM); 148 outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
149 uhci->io_addr + USBFRNUM);
150 150
151 /* Mark controller as not halted before we enable interrupts */ 151 /* Mark controller as not halted before we enable interrupts */
152 uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED; 152 uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
@@ -239,7 +239,6 @@ __acquires(uhci->lock)
239 dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); 239 dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
240 240
241 uhci_get_current_frame_number(uhci); 241 uhci_get_current_frame_number(uhci);
242 smp_wmb();
243 242
244 uhci->rh_state = new_state; 243 uhci->rh_state = new_state;
245 uhci->is_stopped = UHCI_IS_STOPPED; 244 uhci->is_stopped = UHCI_IS_STOPPED;
@@ -253,7 +252,6 @@ static void start_rh(struct uhci_hcd *uhci)
253{ 252{
254 uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; 253 uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
255 uhci->is_stopped = 0; 254 uhci->is_stopped = 0;
256 smp_wmb();
257 255
258 /* Mark it configured and running with a 64-byte max packet. 256 /* Mark it configured and running with a 64-byte max packet.
259 * All interrupts are enabled, even though RESUME won't do anything. 257 * All interrupts are enabled, even though RESUME won't do anything.
@@ -360,12 +358,21 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
360 358
361/* 359/*
362 * Store the current frame number in uhci->frame_number if the controller 360 * Store the current frame number in uhci->frame_number if the controller
363 * is runnning 361 * is runnning. Expand from 11 bits (of which we use only 10) to a
362 * full-sized integer.
363 *
364 * Like many other parts of the driver, this code relies on being polled
365 * more than once per second as long as the controller is running.
364 */ 366 */
365static void uhci_get_current_frame_number(struct uhci_hcd *uhci) 367static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
366{ 368{
367 if (!uhci->is_stopped) 369 if (!uhci->is_stopped) {
368 uhci->frame_number = inw(uhci->io_addr + USBFRNUM); 370 unsigned delta;
371
372 delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) &
373 (UHCI_NUMFRAMES - 1);
374 uhci->frame_number += delta;
375 }
369} 376}
370 377
371/* 378/*
@@ -798,18 +805,15 @@ done:
798static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) 805static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
799{ 806{
800 struct uhci_hcd *uhci = hcd_to_uhci(hcd); 807 struct uhci_hcd *uhci = hcd_to_uhci(hcd);
801 unsigned long flags; 808 unsigned frame_number;
802 int is_stopped; 809 unsigned delta;
803 int frame_number;
804 810
805 /* Minimize latency by avoiding the spinlock */ 811 /* Minimize latency by avoiding the spinlock */
806 local_irq_save(flags); 812 frame_number = uhci->frame_number;
807 is_stopped = uhci->is_stopped; 813 barrier();
808 smp_rmb(); 814 delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) &
809 frame_number = (is_stopped ? uhci->frame_number : 815 (UHCI_NUMFRAMES - 1);
810 inw(uhci->io_addr + USBFRNUM)); 816 return frame_number + delta;
811 local_irq_restore(flags);
812 return frame_number;
813} 817}
814 818
815static const char hcd_name[] = "uhci_hcd"; 819static const char hcd_name[] = "uhci_hcd";
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 04938e64799f..c87ceaa178b6 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -448,6 +448,9 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
448 448
449#define uhci_dev(u) (uhci_to_hcd(u)->self.controller) 449#define uhci_dev(u) (uhci_to_hcd(u)->self.controller)
450 450
451/* Utility macro for comparing frame numbers */
452#define uhci_frame_before_eq(f1, f2) (0 <= (int) ((f2) - (f1)))
453
451 454
452/* 455/*
453 * Private per-URB data 456 * Private per-URB data