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

[PATCH] USB: ehci-hcd, misc bugfixes

This fixes some bugs observed in the EHCI code:

  - Byte-order confusion caused the wrong address to be set
    on big-endian hardware (reported last week on PPC and
    SPARC).   That bug's been there for about a year, with
    no problem reports ... hmm.

  - Used the wrong bitmask to determine max packet size
    for interrupt transfers, so they were limited to 1023
    bytes (not 1024 bytes) at high speed.

  - Because those two problems related to the masking,
    I sanity checked it and moved more of byteswapping
    to compile time.

  - Removes some oopsing in the (debug) periodic schedule
    dump, seen with patches that add more interesting
    behaviors (which folk are finally trying...).

  - Removed some now-pointless <linux/version.h> usage
parent 90b2bb9e
...@@ -465,7 +465,7 @@ show_periodic (struct class_device *class_dev, char *buf) ...@@ -465,7 +465,7 @@ show_periodic (struct class_device *class_dev, char *buf)
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < ehci->periodic_size; i++) { for (i = 0; i < ehci->periodic_size; i++) {
p = ehci->pshadow [i]; p = ehci->pshadow [i];
if (!p.ptr) if (likely (!p.ptr))
continue; continue;
tag = Q_NEXT_TYPE (ehci->periodic [i]); tag = Q_NEXT_TYPE (ehci->periodic [i]);
...@@ -495,7 +495,7 @@ show_periodic (struct class_device *class_dev, char *buf) ...@@ -495,7 +495,7 @@ show_periodic (struct class_device *class_dev, char *buf)
break; break;
} }
/* show more info the first time around */ /* show more info the first time around */
if (temp == seen_count) { if (temp == seen_count && p.ptr) {
u32 scratch = cpu_to_le32p ( u32 scratch = cpu_to_le32p (
&p.qh->hw_info1); &p.qh->hw_info1);
struct ehci_qtd *qtd; struct ehci_qtd *qtd;
...@@ -528,8 +528,10 @@ show_periodic (struct class_device *class_dev, char *buf) ...@@ -528,8 +528,10 @@ show_periodic (struct class_device *class_dev, char *buf)
seen [seen_count++].qh = p.qh; seen [seen_count++].qh = p.qh;
} else } else
temp = 0; temp = 0;
tag = Q_NEXT_TYPE (p.qh->hw_next); if (p.qh) {
p = p.qh->qh_next; tag = Q_NEXT_TYPE (p.qh->hw_next);
p = p.qh->qh_next;
}
break; break;
case Q_TYPE_FSTN: case Q_TYPE_FSTN:
temp = snprintf (next, size, temp = snprintf (next, size,
......
...@@ -184,7 +184,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs) ...@@ -184,7 +184,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */ /* S-mask in a QH means it's an interrupt urb */
if ((qh->hw_info2 & cpu_to_le32 (0x00ff)) != 0) { if ((qh->hw_info2 & __constant_cpu_to_le32 (0x00ff)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */ /* ... update hc-wide periodic stats (for usbfs) */
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--; hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
...@@ -224,7 +224,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs) ...@@ -224,7 +224,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
* Chases up to qh->hw_current. Returns number of completions called, * Chases up to qh->hw_current. Returns number of completions called,
* indicating how much "real" work we did. * indicating how much "real" work we did.
*/ */
#define HALT_BIT cpu_to_le32(QTD_STS_HALT) #define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
static unsigned static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
{ {
...@@ -377,10 +377,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs) ...@@ -377,10 +377,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
return count; return count;
} }
#undef HALT_BIT
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
// ... and packet size, for any kind of endpoint descriptor
#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
/* /*
* reverse of qh_urb_transaction: free a list of TDs. * reverse of qh_urb_transaction: free a list of TDs.
* used for cleanup after errors, before HC sees an URB's TDs. * used for cleanup after errors, before HC sees an URB's TDs.
...@@ -461,7 +465,7 @@ qh_urb_transaction ( ...@@ -461,7 +465,7 @@ qh_urb_transaction (
token |= (1 /* "in" */ << 8); token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */ /* else it's already initted to "out" pid (0 << 8) */
maxpacket = usb_maxpacket (urb->dev, urb->pipe, !is_input) & 0x03ff; maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
/* /*
* buffer gets wrapped in one or more qtds; * buffer gets wrapped in one or more qtds;
...@@ -564,11 +568,6 @@ clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh) ...@@ -564,11 +568,6 @@ clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
// That'd mean updating how usbcore talks to HCDs. (2.5?) // That'd mean updating how usbcore talks to HCDs. (2.5?)
// high bandwidth multiplier, as encoded in highspeed endpoint descriptors
#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
// ... and packet size, for any kind of endpoint descriptor
#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x03ff)
/* /*
* Each QH holds a qtd list; a QH is used for everything except iso. * Each QH holds a qtd list; a QH is used for everything except iso.
* *
...@@ -728,7 +727,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -728,7 +727,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
} }
} }
qh->hw_token &= ~__constant_cpu_to_le32 (QTD_STS_HALT); qh->hw_token &= ~HALT_BIT;
/* splice right after start */ /* splice right after start */
qh->qh_next = head->qh_next; qh->qh_next = head->qh_next;
...@@ -744,6 +743,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -744,6 +743,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#define QH_ADDR_MASK __constant_le32_to_cpu(0x7f)
/* /*
* For control/bulk/interrupt, return QH with these TDs appended. * For control/bulk/interrupt, return QH with these TDs appended.
* Allocates and initializes the QH if necessary. * Allocates and initializes the QH if necessary.
...@@ -778,12 +779,13 @@ static struct ehci_qh *qh_append_tds ( ...@@ -778,12 +779,13 @@ static struct ehci_qh *qh_append_tds (
/* control qh may need patching after enumeration */ /* control qh may need patching after enumeration */
if (unlikely (epnum == 0)) { if (unlikely (epnum == 0)) {
/* set_address changes the address */ /* set_address changes the address */
if (le32_to_cpu (qh->hw_info1 & 0x7f) == 0) if ((qh->hw_info1 & QH_ADDR_MASK) == 0)
qh->hw_info1 |= cpu_to_le32 ( qh->hw_info1 |= cpu_to_le32 (
usb_pipedevice (urb->pipe)); usb_pipedevice (urb->pipe));
/* for full speed, ep0 maxpacket can grow */ /* for full speed, ep0 maxpacket can grow */
else if (!(qh->hw_info1 & cpu_to_le32 (0x3 << 12))) { else if (!(qh->hw_info1
& __constant_cpu_to_le32 (0x3 << 12))) {
u32 info, max; u32 info, max;
info = le32_to_cpu (qh->hw_info1); info = le32_to_cpu (qh->hw_info1);
...@@ -797,7 +799,7 @@ static struct ehci_qh *qh_append_tds ( ...@@ -797,7 +799,7 @@ static struct ehci_qh *qh_append_tds (
/* usb_reset_device() briefly reverts to address 0 */ /* usb_reset_device() briefly reverts to address 0 */
if (usb_pipedevice (urb->pipe) == 0) if (usb_pipedevice (urb->pipe) == 0)
qh->hw_info1 &= cpu_to_le32(~0x7f); qh->hw_info1 &= ~QH_ADDR_MASK;
} }
/* usb_clear_halt() means qh data toggle gets reset */ /* usb_clear_halt() means qh data toggle gets reset */
...@@ -833,7 +835,7 @@ static struct ehci_qh *qh_append_tds ( ...@@ -833,7 +835,7 @@ static struct ehci_qh *qh_append_tds (
* HC is allowed to fetch the old dummy (4.10.2). * HC is allowed to fetch the old dummy (4.10.2).
*/ */
token = qtd->hw_token; token = qtd->hw_token;
qtd->hw_token = cpu_to_le32 (QTD_STS_HALT); qtd->hw_token = HALT_BIT;
wmb (); wmb ();
dummy = qh->dummy; dummy = qh->dummy;
......
...@@ -325,6 +325,7 @@ union ehci_shadow { ...@@ -325,6 +325,7 @@ union ehci_shadow {
struct ehci_itd *itd; /* Q_TYPE_ITD */ struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */ struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */ struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
u32 *hw_next; /* (all types) */
void *ptr; void *ptr;
}; };
...@@ -469,27 +470,12 @@ struct ehci_fstn { ...@@ -469,27 +470,12 @@ struct ehci_fstn {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,32)
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb)
#define STUB_DEBUG_FILES
static inline int hcd_register_root (struct usb_hcd *hcd)
{
return usb_new_device (hcd_to_bus (hcd)->root_hub);
}
#else /* LINUX_VERSION_CODE */
#define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags) #define SUBMIT_URB(urb,mem_flags) usb_submit_urb(urb,mem_flags)
#ifndef DEBUG #ifndef DEBUG
#define STUB_DEBUG_FILES #define STUB_DEBUG_FILES
#endif /* DEBUG */ #endif /* DEBUG */
#endif /* LINUX_VERSION_CODE */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#endif /* __LINUX_EHCI_HCD_H */ #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