Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4334726 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

[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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 3612242e
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -289,7 +289,7 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
	unsigned short portsc1, portsc2;

	/* Try to make sure there's enough memory */
	if (len < 80 * 6)
	if (len < 80 * 9)
		return 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 += uhci_show_sc(1, portsc1, 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;
}
+22 −18
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@
 * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
 *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
 * (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
 * are no royalties or anything like that, but even so there are
@@ -31,7 +31,6 @@
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/unistd.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);

	/* 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 */
	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");

	uhci_get_current_frame_number(uhci);
	smp_wmb();

	uhci->rh_state = new_state;
	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->is_stopped = 0;
	smp_wmb();

	/* Mark it configured and running with a 64-byte max packet.
	 * 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
 * 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)
{
	if (!uhci->is_stopped)
		uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
	if (!uhci->is_stopped) {
		unsigned delta;

		delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) &
				(UHCI_NUMFRAMES - 1);
		uhci->frame_number += delta;
	}
}

/*
@@ -798,18 +805,15 @@ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
{
	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
	unsigned long flags;
	int is_stopped;
	int frame_number;
	unsigned frame_number;
	unsigned delta;

	/* Minimize latency by avoiding the spinlock */
	local_irq_save(flags);
	is_stopped = uhci->is_stopped;
	smp_rmb();
	frame_number = (is_stopped ? uhci->frame_number :
			inw(uhci->io_addr + USBFRNUM));
	local_irq_restore(flags);
	return frame_number;
	frame_number = uhci->frame_number;
	barrier();
	delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) &
			(UHCI_NUMFRAMES - 1);
	return frame_number + delta;
}

static const char hcd_name[] = "uhci_hcd";
+3 −0
Original line number Diff line number Diff line
@@ -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)

/* Utility macro for comparing frame numbers */
#define uhci_frame_before_eq(f1, f2)	(0 <= (int) ((f2) - (f1)))


/*
 *	Private per-URB data