Commit e0901283 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

USB

ehci-0306, iso, philips, speedups
  
      - adds preliminary highspeed ISO support
      - tweaks the driver to support the Philips EHCI
      - does less in the IRQ handler
      - avoids accessing one immutable PCI register
  
The ISO support should be enough to start writing
drivers, not that I know of any ISO devices that are
really available yet, but it's not fully cooked yet.
  
As a functional milestone, this means Linux now
handles all kinds of highspeed device I/O.  (But it
doesn't yet handle split periodic transactions, to
full or low speed devices through USB 2.0 hubs.)
    
Thanks to Rory Bolt for the non-ISO bits here!
parent ddbdbc8c
/*
* Copyright (c) 2000-2001 by David Brownell
* Copyright (c) 2000-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
......@@ -31,10 +31,6 @@
#include <linux/list.h>
#include <linux/interrupt.h>
#ifndef CONFIG_USB_DEBUG
#define CONFIG_USB_DEBUG /* this is still experimental! */
#endif
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
......@@ -73,19 +69,25 @@
* ...
*
* HISTORY:
*
* 2002-03-05 Initial high-speed ISO support; reduce ITD memory; shift
* more checking to generic hcd framework (db). Make it work with
* Philips EHCI; reduce PCI traffic; shorten IRQ path (Rory Bolt).
* 2002-01-14 Minor cleanup; version synch.
* 2002-01-08 Fix roothub handoff of FS/LS to companion controllers.
* 2002-01-04 Control/Bulk queuing behaves.
*
* 2001-12-12 Initial patch version for Linux 2.5.1 kernel.
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
#define DRIVER_VERSION "$Revision: 0.26 $"
#define DRIVER_VERSION "$Revision: 0.27 $"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
// #define EHCI_VERBOSE_DEBUG
// #define have_iso
// #define have_split_iso
#ifdef CONFIG_DEBUG_SLAB
# define EHCI_SLAB_FLAGS (SLAB_POISON)
......@@ -187,6 +189,9 @@ static int ehci_start (struct usb_hcd *hcd)
dbg_hcs_params (ehci, "ehci_start");
dbg_hcc_params (ehci, "ehci_start");
/* cache this readonly data; minimize PCI reads */
ehci->hcs_params = readl (&ehci->caps->hcs_params);
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
......@@ -204,7 +209,7 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->async = 0;
ehci->reclaim = 0;
ehci->next_frame = -1;
ehci->next_uframe = -1;
/* controller state: unknown --> reset */
......@@ -310,7 +315,7 @@ static void ehci_stop (struct usb_hcd *hcd)
// root hub is shut down separately (first, when possible)
scan_async (ehci);
if (ehci->next_frame != -1)
if (ehci->next_uframe != -1)
scan_periodic (ehci);
ehci_mem_cleanup (ehci);
......@@ -332,14 +337,12 @@ static int ehci_get_frame (struct usb_hcd *hcd)
static int ehci_suspend (struct usb_hcd *hcd, u32 state)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 params;
int ports;
int i;
dbg ("%s: suspend to %d", hcd->bus_name, state);
params = readl (&ehci->caps->hcs_params);
ports = HCS_N_PORTS (params);
ports = HCS_N_PORTS (ehci->hcs_params);
// FIXME: This assumes what's probably a D3 level suspend...
......@@ -375,14 +378,12 @@ dbg ("%s: suspend port %d", hcd->bus_name, i);
static int ehci_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 params;
int ports;
int i;
dbg ("%s: resume", hcd->bus_name);
params = readl (&ehci->caps->hcs_params);
ports = HCS_N_PORTS (params);
ports = HCS_N_PORTS (ehci->hcs_params);
// FIXME: if controller didn't retain state,
// return and let generic code clean it up
......@@ -426,7 +427,7 @@ static void ehci_tasklet (unsigned long param)
if (ehci->reclaim_ready)
end_unlink_async (ehci);
scan_async (ehci);
if (ehci->next_frame != -1)
if (ehci->next_uframe != -1)
scan_periodic (ehci);
// FIXME: when nothing is connected to the root hub,
......@@ -440,19 +441,19 @@ static void ehci_irq (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 status = readl (&ehci->regs->status);
int bh = 0;
int bh;
/* clear (just) interrupts */
status &= INTR_MASK;
if (!status) /* irq sharing? */
return;
/* clear (just) interrupts */
writel (status, &ehci->regs->status);
readl (&ehci->regs->command); /* unblock posted write */
if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
return;
bh = 0;
#ifdef EHCI_VERBOSE_DEBUG
/* unrequested/ignored: Port Change Detect, Frame List Rollover */
if (status & INTR_MASK)
dbg_status (ehci, "irq", status);
#endif
......@@ -520,17 +521,15 @@ static int ehci_urb_enqueue (
return intr_submit (ehci, urb, &qtd_list, mem_flags);
case PIPE_ISOCHRONOUS:
#ifdef have_iso
if (urb->dev->speed == USB_SPEED_HIGH)
return itd_submit (ehci, urb);
return itd_submit (ehci, urb, mem_flags);
#ifdef have_split_iso
else
return sitd_submit (ehci, urb);
return sitd_submit (ehci, urb, mem_flags);
#else
// FIXME highspeed iso stuff is written but never run/tested.
// and the split iso support isn't even written yet.
dbg ("no iso support yet");
dbg ("no split iso support yet");
return -ENOSYS;
#endif /* have_iso */
#endif /* have_split_iso */
}
return 0;
......
/*
* Copyright (c) 2001 by David Brownell
* Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
......@@ -68,8 +68,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* init status to no-changes */
buf [0] = 0;
temp = readl (&ehci->caps->hcs_params);
ports = HCS_N_PORTS (temp);
ports = HCS_N_PORTS (ehci->hcs_params);
if (ports > 7) {
buf [1] = 0;
retval++;
......@@ -107,8 +106,7 @@ ehci_hub_descriptor (
struct ehci_hcd *ehci,
struct usb_hub_descriptor *desc
) {
u32 params = readl (&ehci->caps->hcs_params);
int ports = HCS_N_PORTS (params);
int ports = HCS_N_PORTS (ehci->hcs_params);
u16 temp;
desc->bDescriptorType = 0x29;
......@@ -124,10 +122,10 @@ ehci_hub_descriptor (
memset (&desc->bitmap [temp], 0xff, temp);
temp = 0x0008; /* per-port overcurrent reporting */
if (HCS_PPC (params)) /* per-port power control */
temp |= 0x0001;
if (HCS_INDICATOR (params)) /* per-port indicators (LEDs) */
temp |= 0x0080;
if (HCS_PPC (ehci->hcs_params))
temp |= 0x0001; /* per-port power control */
if (HCS_INDICATOR (ehci->hcs_params))
temp |= 0x0080; /* per-port indicators (LEDs) */
desc->wHubCharacteristics = cpu_to_le16 (temp);
}
......@@ -142,8 +140,7 @@ static int ehci_hub_control (
u16 wLength
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 params = readl (&ehci->caps->hcs_params);
int ports = HCS_N_PORTS (params);
int ports = HCS_N_PORTS (ehci->hcs_params);
u32 temp;
unsigned long flags;
int retval = 0;
......@@ -189,7 +186,7 @@ static int ehci_hub_control (
/* ? */
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (params))
if (HCS_PPC (ehci->hcs_params))
writel (temp & ~PORT_POWER,
&ehci->regs->port_status [wIndex]);
break;
......@@ -300,7 +297,7 @@ static int ehci_hub_control (
&ehci->regs->port_status [wIndex]);
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (params))
if (HCS_PPC (ehci->hcs_params))
writel (temp | PORT_POWER,
&ehci->regs->port_status [wIndex]);
break;
......@@ -312,6 +309,13 @@ static int ehci_hub_control (
hcd->bus_name, wIndex + 1);
temp |= PORT_OWNER;
} else {
/* Philips 1562 wants CMD_RUN to reset */
if (!HCD_IS_RUNNING(ehci->hcd.state)) {
u32 cmd = readl (&ehci->regs->command);
cmd |= CMD_RUN;
writel (cmd, &ehci->regs->command);
ehci->hcd.state = USB_STATE_RUNNING;
}
vdbg ("%s port %d reset",
hcd->bus_name, wIndex + 1);
temp |= PORT_RESET;
......
/*
* Copyright (c) 2001 by David Brownell
* Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
......@@ -643,12 +643,19 @@ ehci_qh_make (
if (usb_pipecontrol (urb->pipe)) {
info1 |= 64 << 16; /* usb2 fixed maxpacket */
info1 |= 1 << 14; /* toggle from qtd */
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else if (usb_pipebulk (urb->pipe)) {
info1 |= 512 << 16; /* usb2 fixed maxpacket */
info2 |= (EHCI_TUNE_MULT_HS << 30);
} else
info1 |= usb_maxpacket (urb->dev, urb->pipe,
usb_pipeout (urb->pipe)) << 16;
} else {
u32 temp;
temp = usb_maxpacket (urb->dev, urb->pipe,
usb_pipeout (urb->pipe));
info1 |= (temp & 0x3ff) << 16; /* maxpacket */
/* HS intr can be "high bandwidth" */
temp = 1 + ((temp >> 11) & 0x03);
info2 |= temp << 30; /* mult */
}
break;
default:
#ifdef DEBUG
......
This diff is collapsed.
/*
* Copyright (c) 2001 by David Brownell
* Copyright (c) 2001-2002 by David Brownell
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
......@@ -49,7 +49,7 @@ struct ehci_hcd { /* one per controller */
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
int next_frame; /* scan periodic, start here */
int next_uframe; /* scan periodic, start here */
unsigned periodic_urbs; /* how many urbs scheduled? */
/* deferred work from IRQ, etc */
......@@ -62,6 +62,7 @@ struct ehci_hcd { /* one per controller */
struct usb_hcd hcd;
struct ehci_caps *caps;
struct ehci_regs *regs;
u32 hcs_params; /* cached register copy */
/* per-HC memory pools (could be per-PCI-bus, but ...) */
struct pci_pool *qh_pool; /* qh per active urb */
......@@ -324,13 +325,14 @@ struct ehci_itd {
union ehci_shadow itd_next; /* ptr to periodic q entry */
struct urb *urb;
unsigned index; /* in urb->iso_frame_desc */
struct list_head itd_list; /* list of urb frames' itds */
dma_addr_t buf_dma; /* frame's buffer address */
unsigned uframe; /* in periodic schedule */
u32 transaction [8]; /* copy of hw_transaction */
/* for now, only one hw_transaction per itd */
u32 transaction;
u16 index; /* in urb->iso_frame_desc */
u16 uframe; /* in periodic schedule */
u16 usecs;
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment