1
0
Fork 0

[PATCH] UHCI: use integer-sized frame numbers

This patch (as687) changes uhci-hcd to keep track of frame numbers as
full-sized integers rather than 11-bit values.  This makes them a lot
easier to handle and makes it possible to schedule beyond a 2-second
window, should anyone ever want to do so.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
hifive-unleashed-5.1
Alan Stern 2006-05-19 16:34:57 -04:00 committed by Greg Kroah-Hartman
parent 3612242e52
commit c433472658
3 changed files with 28 additions and 19 deletions

View File

@ -289,7 +289,7 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
unsigned short portsc1, portsc2; unsigned short portsc1, portsc2;
/* Try to make sure there's enough memory */ /* Try to make sure there's enough memory */
if (len < 80 * 6) if (len < 80 * 9)
return 0; return 0;
usbcmd = inw(io_addr + 0); usbcmd = inw(io_addr + 0);
@ -328,6 +328,8 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
out += sprintf(out, " sof = %02x\n", sof); out += sprintf(out, " sof = %02x\n", sof);
out += uhci_show_sc(1, portsc1, out, len - (out - buf)); out += uhci_show_sc(1, portsc1, out, len - (out - buf));
out += uhci_show_sc(2, portsc2, out, len - (out - buf)); out += uhci_show_sc(2, portsc2, out, len - (out - buf));
out += sprintf(out, "Most recent frame: %x\n",
uhci->frame_number);
return out - buf; return out - buf;
} }

View File

@ -13,7 +13,7 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com). * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c) * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
* (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
* *
* Intel documents this fairly well, and as far as I know there * Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are * are no royalties or anything like that, but even so there are
@ -31,7 +31,6 @@
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
@ -146,7 +145,8 @@ static void configure_hc(struct uhci_hcd *uhci)
outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD); outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
/* Set the current frame number */ /* Set the current frame number */
outw(uhci->frame_number, uhci->io_addr + USBFRNUM); outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
uhci->io_addr + USBFRNUM);
/* Mark controller as not halted before we enable interrupts */ /* Mark controller as not halted before we enable interrupts */
uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED; uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
@ -239,7 +239,6 @@ __acquires(uhci->lock)
dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n"); dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
uhci_get_current_frame_number(uhci); uhci_get_current_frame_number(uhci);
smp_wmb();
uhci->rh_state = new_state; uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED; uhci->is_stopped = UHCI_IS_STOPPED;
@ -253,7 +252,6 @@ static void start_rh(struct uhci_hcd *uhci)
{ {
uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
uhci->is_stopped = 0; uhci->is_stopped = 0;
smp_wmb();
/* Mark it configured and running with a 64-byte max packet. /* Mark it configured and running with a 64-byte max packet.
* All interrupts are enabled, even though RESUME won't do anything. * 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)
/* /*
* Store the current frame number in uhci->frame_number if the controller * Store the current frame number in uhci->frame_number if the controller
* is runnning * is runnning. Expand from 11 bits (of which we use only 10) to a
* full-sized integer.
*
* Like many other parts of the driver, this code relies on being polled
* more than once per second as long as the controller is running.
*/ */
static void uhci_get_current_frame_number(struct uhci_hcd *uhci) static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
{ {
if (!uhci->is_stopped) if (!uhci->is_stopped) {
uhci->frame_number = inw(uhci->io_addr + USBFRNUM); unsigned delta;
delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) &
(UHCI_NUMFRAMES - 1);
uhci->frame_number += delta;
}
} }
/* /*
@ -798,18 +805,15 @@ done:
static int uhci_hcd_get_frame_number(struct usb_hcd *hcd) static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
{ {
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags; unsigned frame_number;
int is_stopped; unsigned delta;
int frame_number;
/* Minimize latency by avoiding the spinlock */ /* Minimize latency by avoiding the spinlock */
local_irq_save(flags); frame_number = uhci->frame_number;
is_stopped = uhci->is_stopped; barrier();
smp_rmb(); delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) &
frame_number = (is_stopped ? uhci->frame_number : (UHCI_NUMFRAMES - 1);
inw(uhci->io_addr + USBFRNUM)); return frame_number + delta;
local_irq_restore(flags);
return frame_number;
} }
static const char hcd_name[] = "uhci_hcd"; static const char hcd_name[] = "uhci_hcd";

View File

@ -448,6 +448,9 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
#define uhci_dev(u) (uhci_to_hcd(u)->self.controller) #define uhci_dev(u) (uhci_to_hcd(u)->self.controller)
/* Utility macro for comparing frame numbers */
#define uhci_frame_before_eq(f1, f2) (0 <= (int) ((f2) - (f1)))
/* /*
* Private per-URB data * Private per-URB data