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

[PATCH] Re: updated ehci patch ...

 * keep watchdog on shorter leash, and just do
   standard irq processing when it barks.  this
   means I can use a somewhat iffy vt8235 mobo.

 * updates to the driverfs debug output, including
   using S_IRUGO so anyone can gawk.

 * some updates, mostly to use a new hcd_to_bus(),
   so this version also compiles on a (slightly
   patched) 2.4.20-pre5 kernel.  (*)
parent 2ee2c1ed
......@@ -57,7 +57,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
strcat(buf, tmp);
}
dbg ("%s: %s portroute %s",
ehci->hcd.self.bus_name, label,
hcd_to_bus (&ehci->hcd)->bus_name, label,
buf);
}
}
......@@ -122,7 +122,8 @@ dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
}
}
static int dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
static int __attribute__((__unused__))
dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
{
return snprintf (buf, len,
"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
......@@ -140,7 +141,8 @@ static int dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
);
}
static int dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
static int __attribute__((__unused__))
dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
{
return snprintf (buf, len,
"%s%sintrenable %02x%s%s%s%s%s%s",
......@@ -213,19 +215,19 @@ dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
static inline int __attribute__((__unused__))
dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
{}
{ return 0; }
static inline int __attribute__((__unused__))
dbg_command_buf (char *buf, unsigned len, char *label, u32 command)
{}
{ return 0; }
static inline int __attribute__((__unused__))
dbg_intr_buf (char *buf, unsigned len, char *label, u32 enable)
{}
{ return 0; }
static inline int __attribute__((__unused__))
dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
{}
{ return 0; }
#endif /* DEBUG */
......@@ -248,7 +250,16 @@ dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
dbg ("%s", _buf); \
}
#ifdef DEBUG
/*-------------------------------------------------------------------------*/
#ifdef STUB_DEBUG_FILES
static inline void create_debug_files (struct ehci_hcd *bus) { }
static inline void remove_debug_files (struct ehci_hcd *bus) { }
#else
/* troubleshooting help: expose state in driverfs */
#define speed_char(info1) ({ char tmp; \
switch (info1 & (3 << 12)) { \
......@@ -258,6 +269,49 @@ dbg_port_buf (char *buf, unsigned len, char *label, int port, u32 status)
default: tmp = '?'; break; \
}; tmp; })
static void qh_lines (struct ehci_qh *qh, char **nextp, unsigned *sizep)
{
u32 scratch;
struct list_head *entry;
struct ehci_qtd *td;
unsigned temp;
unsigned size = *sizep;
char *next = *nextp;
scratch = cpu_to_le32p (&qh->hw_info1);
temp = snprintf (next, size, "qh/%p dev%d %cs ep%d %08x %08x",
qh, scratch & 0x007f,
speed_char (scratch),
(scratch >> 8) & 0x000f,
scratch, cpu_to_le32p (&qh->hw_info2));
size -= temp;
next += temp;
list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd,
qtd_list);
scratch = cpu_to_le32p (&td->hw_token);
temp = snprintf (next, size,
"\n\ttd/%p %s len=%d %08x urb %p",
td, ({ char *tmp;
switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break;
case 1: tmp = "in"; break;
case 2: tmp = "setup"; break;
default: tmp = "?"; break;
} tmp;}),
(scratch >> 16) & 0x7fff,
scratch,
td->urb);
size -= temp;
next += temp;
}
temp = snprintf (next, size, "\n");
*sizep = size - temp;
*nextp = next + temp;
}
static ssize_t
show_async (struct device *dev, char *buf, size_t count, loff_t off)
{
......@@ -284,49 +338,21 @@ show_async (struct device *dev, char *buf, size_t count, loff_t off)
if (ehci->async) {
qh = ehci->async;
do {
u32 scratch;
struct list_head *entry;
struct ehci_qtd *td;
scratch = cpu_to_le32p (&qh->hw_info1);
temp = snprintf (next, size, "qh %p dev%d %cs ep%d",
qh, scratch & 0x007f,
speed_char (scratch),
(scratch >> 8) & 0x000f);
size -= temp;
next += temp;
list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd,
qtd_list);
scratch = cpu_to_le32p (&td->hw_token);
temp = snprintf (next, size,
", td %p len=%d tok %04x %s",
td, scratch >> 16,
scratch & 0xffff,
({ char *tmp;
switch ((scratch>>8)&0x03) {
case 0: tmp = "out"; break;
case 1: tmp = "in"; break;
case 2: tmp = "setup"; break;
default: tmp = "?"; break;
} tmp;})
);
size -= temp;
next += temp;
}
temp = snprintf (next, size, "\n");
size -= temp;
next += temp;
qh_lines (qh, &next, &size);
} while ((qh = qh->qh_next.qh) != ehci->async);
}
if (ehci->reclaim) {
temp = snprintf (next, size, "\nreclaim =\n");
size -= temp;
next += temp;
qh_lines (ehci->reclaim, &next, &size);
}
spin_unlock_irqrestore (&ehci->lock, flags);
return count - size;
}
static DEVICE_ATTR (async, S_IRUSR, show_async, NULL);
static DEVICE_ATTR (async, S_IRUGO, show_async, NULL);
#define DBG_SCHED_LIMIT 64
......@@ -373,7 +399,7 @@ show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
do {
switch (tag) {
case Q_TYPE_QH:
temp = snprintf (next, size, " intr-%d %p",
temp = snprintf (next, size, " qh%d/%p",
p.qh->period, p.qh);
size -= temp;
next += temp;
......@@ -387,12 +413,14 @@ show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
&p.qh->hw_info1);
temp = snprintf (next, size,
" (%cs dev%d ep%d)",
" (%cs dev%d ep%d [%d/%d] %d)",
speed_char (scratch),
scratch & 0x007f,
(scratch >> 8) & 0x000f);
(scratch >> 8) & 0x000f,
p.qh->usecs, p.qh->c_usecs,
scratch >> 16);
/* FIXME TDs too */
/* FIXME TD info too */
if (seen_count < DBG_SCHED_LIMIT)
seen [seen_count++].qh = p.qh;
......@@ -434,7 +462,7 @@ show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
return count - size;
}
static DEVICE_ATTR (periodic, S_IRUSR, show_periodic, NULL);
static DEVICE_ATTR (periodic, S_IRUGO, show_periodic, NULL);
#undef DBG_SCHED_LIMIT
......@@ -522,7 +550,7 @@ show_registers (struct device *dev, char *buf, size_t count, loff_t off)
return count - size;
}
static DEVICE_ATTR (registers, S_IRUSR, show_registers, NULL);
static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
static inline void create_debug_files (struct ehci_hcd *bus)
{
......@@ -538,14 +566,5 @@ static inline void remove_debug_files (struct ehci_hcd *bus)
device_remove_file (&bus->hcd.pdev->dev, &dev_attr_registers);
}
#else /* DEBUG */
static inline void create_debug_files (struct ehci_hcd *bus)
{
}
static inline void remove_debug_files (struct ehci_hcd *bus)
{
}
#endif /* STUB_DEBUG_FILES */
#endif /* DEBUG */
......@@ -38,7 +38,12 @@
#endif
#include <linux/usb.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
#include "../hcd.h"
#else
#include "../core/hcd.h"
#endif
#include <asm/byteorder.h>
#include <asm/io.h>
......@@ -104,7 +109,7 @@
#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
#define EHCI_TUNE_MULT_TT 1
#define EHCI_WATCHDOG_JIFFIES (HZ/10) /* arbitrary; ~100 msec */
#define EHCI_WATCHDOG_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
/* Initial IRQ latency: lower than default */
static int log2_irq_thresh = 0; // 0 to 6
......@@ -234,6 +239,8 @@ static void ehci_ready (struct ehci_hcd *ehci)
static void ehci_tasklet (unsigned long param);
static void ehci_irq (struct usb_hcd *hcd);
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
......@@ -241,14 +248,8 @@ static void ehci_watchdog (unsigned long param)
/* guard against lost IAA, which wedges everything */
spin_lock_irqsave (&ehci->lock, flags);
if (ehci->reclaim) {
err ("%s watchdog, reclaim qh %p%s", ehci->hcd.self.bus_name,
ehci->reclaim, ehci->reclaim_ready ? " ready" : "");
// ehci->reclaim_ready = 1;
tasklet_schedule (&ehci->tasklet);
}
ehci_irq (&ehci->hcd);
spin_unlock_irqrestore (&ehci->lock, flags);
}
/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
......@@ -286,6 +287,7 @@ static int ehci_start (struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
struct usb_device *udev;
struct usb_bus *bus;
int retval;
u32 hcc_params;
u8 tempbyte;
......@@ -396,15 +398,14 @@ static int ehci_start (struct usb_hcd *hcd)
ehci->watchdog.data = (unsigned long) ehci;
/* wire up the root hub */
hcd->self.root_hub = udev = usb_alloc_dev (NULL, &hcd->self);
bus = hcd_to_bus (hcd);
bus->root_hub = udev = usb_alloc_dev (NULL, bus);
if (!udev) {
done2:
ehci_mem_cleanup (ehci);
return -ENOMEM;
}
create_debug_files (ehci);
/*
* Start, enabling full USB 2.0 functionality ... usb 1.1 devices
* are explicitly handed to companion controller(s), so no TT is
......@@ -432,16 +433,22 @@ static int ehci_start (struct usb_hcd *hcd)
*/
usb_connect (udev);
udev->speed = USB_SPEED_HIGH;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
if (usb_new_device (udev) != 0) {
#else
if (usb_register_root_hub (udev, &ehci->hcd.pdev->dev) != 0) {
#endif
if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci);
ehci_reset (ehci);
hcd->self.root_hub = 0;
bus->root_hub = 0;
usb_free_dev (udev);
retval = -ENODEV;
goto done2;
}
create_debug_files (ehci);
return 0;
}
......@@ -451,7 +458,7 @@ static void ehci_stop (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
dbg ("%s: stop", hcd->self.bus_name);
dbg ("%s: stop", hcd_to_bus (hcd)->bus_name);
/* no more interrupts ... */
if (hcd->state == USB_STATE_RUNNING)
......@@ -493,7 +500,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
int ports;
int i;
dbg ("%s: suspend to %d", hcd->self.bus_name, state);
dbg ("%s: suspend to %d", hcd_to_bus (hcd)->bus_name, state);
ports = HCS_N_PORTS (ehci->hcs_params);
......@@ -510,7 +517,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
if ((temp & PORT_PE) == 0
|| (temp & PORT_OWNER) != 0)
continue;
dbg ("%s: suspend port %d", hcd->self.bus_name, i);
dbg ("%s: suspend port %d", hcd_to_bus (hcd)->bus_name, i);
temp |= PORT_SUSPEND;
writel (temp, &ehci->regs->port_status [i]);
}
......@@ -532,7 +539,7 @@ static int ehci_resume (struct usb_hcd *hcd)
int ports;
int i;
dbg ("%s: resume", hcd->self.bus_name);
dbg ("%s: resume", hcd_to_bus (hcd)->bus_name);
ports = HCS_N_PORTS (ehci->hcs_params);
......@@ -552,7 +559,7 @@ static int ehci_resume (struct usb_hcd *hcd)
if ((temp & PORT_PE) == 0
|| (temp & PORT_SUSPEND) != 0)
continue;
dbg ("%s: resume port %d", hcd->self.bus_name, i);
dbg ("%s: resume port %d", hcd_to_bus (hcd)->bus_name, i);
temp |= PORT_RESUME;
writel (temp, &ehci->regs->port_status [i]);
readl (&ehci->regs->command); /* unblock posted writes */
......@@ -599,7 +606,7 @@ static void ehci_irq (struct usb_hcd *hcd)
/* e.g. cardbus physical eject */
if (status == ~(u32) 0) {
dbg ("%s: device removed!", hcd->self.bus_name);
dbg ("%s: device removed!", hcd_to_bus (hcd)->bus_name);
goto dead;
}
......@@ -632,7 +639,7 @@ static void ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
err ("%s: fatal error, state %x",
hcd->self.bus_name, hcd->state);
hcd_to_bus (hcd)->bus_name, hcd->state);
dead:
ehci_reset (ehci);
/* generic layer kills/unlinks all urbs, then
......@@ -708,7 +715,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
unsigned long flags;
dbg ("%s urb_dequeue %p qh %p state %d",
hcd->self.bus_name, urb, qh, qh->qh_state);
hcd_to_bus (hcd)->bus_name, urb, qh, qh->qh_state);
switch (usb_pipetype (urb->pipe)) {
// case PIPE_CONTROL:
......@@ -795,7 +802,8 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
/* ASSERT: no requests/urbs are still linked (so no TDs) */
/* ASSERT: nobody can be submitting urbs for this any more */
dbg ("%s: free_config devnum %d", hcd->self.bus_name, udev->devnum);
dbg ("%s: free_config devnum %d",
hcd_to_bus (hcd)->bus_name, udev->devnum);
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < 32; i++) {
......@@ -816,7 +824,8 @@ static void ehci_free_config (struct usb_hcd *hcd, struct usb_device *udev)
why = 0;
if (why) {
err ("dev %s-%s ep %d-%s error: %s",
hcd->self.bus_name, udev->devpath,
hcd_to_bus (hcd)->bus_name,
udev->devpath,
i & 0xf, (i & 0x10) ? "IN" : "OUT",
why);
BUG ();
......
......@@ -41,14 +41,17 @@ static int check_reset_complete (
/* if reset finished and it's still not enabled -- handoff */
if (!(port_status & PORT_PE)) {
dbg ("%s port %d full speed, give to companion, 0x%x",
ehci->hcd.self.bus_name, index + 1, port_status);
hcd_to_bus (&ehci->hcd)->bus_name,
index + 1, port_status);
// what happens if HCS_N_CC(params) == 0 ?
port_status |= PORT_OWNER;
writel (port_status, &ehci->regs->port_status [index]);
} else
dbg ("%s port %d high speed", ehci->hcd.self.bus_name, index + 1);
dbg ("%s port %d high speed",
hcd_to_bus (&ehci->hcd)->bus_name,
index + 1);
return port_status;
}
......@@ -310,11 +313,13 @@ static int ehci_hub_control (
if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
&& PORT_USB11 (temp)) {
dbg ("%s port %d low speed, give to companion",
hcd->self.bus_name, wIndex + 1);
hcd_to_bus (&ehci->hcd)->bus_name,
wIndex + 1);
temp |= PORT_OWNER;
} else {
vdbg ("%s port %d reset",
hcd->self.bus_name, wIndex + 1);
hcd_to_bus (&ehci->hcd)->bus_name,
wIndex + 1);
temp |= PORT_RESET;
temp &= ~PORT_PE;
......
......@@ -178,7 +178,7 @@ static unsigned long ehci_urb_done (
if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */
ehci->hcd.self.bandwidth_int_reqs--;
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
#ifdef INTR_AUTOMAGIC
if (!((urb->status == -ENOENT)
......@@ -215,7 +215,7 @@ static unsigned long ehci_urb_done (
int status;
resubmit->dev = dev;
status = usb_submit_urb (resubmit, SLAB_KERNEL);
status = SUBMIT_URB (resubmit, SLAB_KERNEL);
if (status != 0)
err ("can't resubmit interrupt urb %p: status %d",
resubmit, status);
......@@ -652,8 +652,8 @@ ehci_qh_make (
info2 |= hb_mult (maxp) << 30;
}
break;
#ifdef DEBUG
default:
#ifdef DEBUG
BUG ();
#endif
}
......@@ -841,7 +841,8 @@ submit_async (
epnum |= 0x10;
vdbg ("%s: submit_async urb %p len %d ep %d-%s qtd %p [qh %p]",
ehci->hcd.self.bus_name, urb, urb->transfer_buffer_length,
hcd_to_bus (&ehci->hcd)->bus_name,
urb, urb->transfer_buffer_length,
epnum & 0x0f, (epnum & 0x10) ? "in" : "out",
qtd, dev ? dev->ep [epnum] : (void *)~0);
......
......@@ -273,7 +273,7 @@ static unsigned long intr_deschedule (
qh->qh_state = QH_STATE_IDLE;
/* update per-qh bandwidth utilization (for usbfs) */
ehci->hcd.self.bandwidth_allocated -=
hcd_to_bus (&ehci->hcd)->bandwidth_allocated -=
(qh->usecs + qh->c_usecs) / qh->period;
vdbg ("descheduled qh %p, per = %d frame = %d count = %d, urbs = %d",
......@@ -435,7 +435,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
} while (frame < ehci->periodic_size);
/* update per-qh bandwidth for usbfs */
ehci->hcd.self.bandwidth_allocated +=
hcd_to_bus (&ehci->hcd)->bandwidth_allocated +=
(qh->usecs + qh->c_usecs) / qh->period;
/* maybe enable periodic schedule processing */
......@@ -485,7 +485,7 @@ static int intr_submit (
BUG_ON (qh == 0);
/* ... update usbfs periodic stats */
ehci->hcd.self.bandwidth_int_reqs++;
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs++;
done:
spin_unlock_irqrestore (&ehci->lock, flags);
......
......@@ -391,4 +391,26 @@ struct ehci_fstn {
union ehci_shadow fstn_next; /* ptr to periodic q entry */
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
#define STUB_DEBUG_FILES
#else /* LINUX_VERSION_CODE */
static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
{ return &hcd->self; }
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
#endif /* LINUX_VERSION_CODE */
/*-------------------------------------------------------------------------*/
#endif /* __LINUX_EHCI_HCD_H */
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