git://git.onelab.eu
/
linux-2.6.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git]
/
drivers
/
usb
/
host
/
ehci-q.c
diff --git
a/drivers/usb/host/ehci-q.c
b/drivers/usb/host/ehci-q.c
index
7df9b9a
..
e469221
100644
(file)
--- a/
drivers/usb/host/ehci-q.c
+++ b/
drivers/usb/host/ehci-q.c
@@
-1,5
+1,5
@@
/*
/*
- * Copyright (
c) 2001-2002
by David Brownell
+ * Copyright (
C) 2001-2004
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
*
* 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
@@
-222,7
+222,7
@@
__acquires(ehci->lock)
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */
- if ((qh->hw_info2 & __constant_cpu_to_le32 (
0x00ff
)) != 0) {
+ if ((qh->hw_info2 & __constant_cpu_to_le32 (
QH_SMASK
)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
/* ... update hc-wide periodic stats (for usbfs) */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
@@
-428,7
+428,8
@@
halt:
/* should be rare for periodic transfers,
* except maybe high bandwidth ...
*/
/* should be rare for periodic transfers,
* except maybe high bandwidth ...
*/
- if (qh->period) {
+ if ((__constant_cpu_to_le32 (QH_SMASK)
+ & qh->hw_info2) != 0) {
intr_deschedule (ehci, qh);
(void) qh_schedule (ehci, qh);
} else
intr_deschedule (ehci, qh);
(void) qh_schedule (ehci, qh);
} else
@@
-476,7
+477,7
@@
qh_urb_transaction (
struct ehci_hcd *ehci,
struct urb *urb,
struct list_head *head,
struct ehci_hcd *ehci,
struct urb *urb,
struct list_head *head,
-
int
flags
+
gfp_t
flags
) {
struct ehci_qtd *qtd, *qtd_prev;
dma_addr_t buf;
) {
struct ehci_qtd *qtd, *qtd_prev;
dma_addr_t buf;
@@
-513,18
+514,18
@@
qh_urb_transaction (
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
+
+ /* for zero length DATA stages, STATUS is always IN */
+ if (len == 0)
+ token |= (1 /* "in" */ << 8);
}
/*
* data transfer stage: buffer setup
*/
}
/*
* data transfer stage: buffer setup
*/
- if (likely (len > 0))
- buf = urb->transfer_dma;
- else
- buf = 0;
+ buf = urb->transfer_dma;
- /* for zero length DATA stages, STATUS is always IN */
- if (!buf || is_input)
+ if (is_input)
token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */
token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */
@@
-571,7
+572,7
@@
qh_urb_transaction (
* control requests may need a terminating data "status" ack;
* bulk ones may need a terminating short packet (zero length).
*/
* control requests may need a terminating data "status" ack;
* bulk ones may need a terminating short packet (zero length).
*/
- if (likely (
buf
!= 0)) {
+ if (likely (
urb->transfer_buffer_length
!= 0)) {
int one_more = 0;
if (usb_pipecontrol (urb->pipe)) {
int one_more = 0;
if (usb_pipecontrol (urb->pipe)) {
@@
-628,7
+629,7
@@
static struct ehci_qh *
qh_make (
struct ehci_hcd *ehci,
struct urb *urb,
qh_make (
struct ehci_hcd *ehci,
struct urb *urb,
-
int
flags
+
gfp_t
flags
) {
struct ehci_qh *qh = ehci_qh_alloc (ehci, flags);
u32 info1 = 0, info2 = 0;
) {
struct ehci_qh *qh = ehci_qh_alloc (ehci, flags);
u32 info1 = 0, info2 = 0;
@@
-657,8
+658,8
@@
qh_make (
* For control/bulk requests, the HC or TT handles these.
*/
if (type == PIPE_INTERRUPT) {
* For control/bulk requests, the HC or TT handles these.
*/
if (type == PIPE_INTERRUPT) {
- qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
- hb_mult (maxp) * max_packet (maxp));
+ qh->usecs =
NS_TO_US (
usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+ hb_mult (maxp) * max_packet (maxp))
)
;
qh->start = NO_FRAME;
if (urb->dev->speed == USB_SPEED_HIGH) {
qh->start = NO_FRAME;
if (urb->dev->speed == USB_SPEED_HIGH) {
@@
-676,6
+677,9
@@
qh_make (
goto done;
}
} else {
goto done;
}
} else {
+ struct usb_tt *tt = urb->dev->tt;
+ int think_time;
+
/* gap is f(FS/LS transfer times) */
qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
is_input, 0, maxp) / (125 * 1000);
/* gap is f(FS/LS transfer times) */
qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
is_input, 0, maxp) / (125 * 1000);
@@
-689,12
+693,16
@@
qh_make (
qh->c_usecs = HS_USECS (0);
}
qh->c_usecs = HS_USECS (0);
}
+ think_time = tt ? tt->think_time : 0;
+ qh->tt_usecs = NS_TO_US (think_time +
+ usb_calc_bus_time (urb->dev->speed,
+ is_input, 0, max_packet (maxp)));
qh->period = urb->interval;
}
}
/* support for tt scheduling, and access to toggles */
qh->period = urb->interval;
}
}
/* support for tt scheduling, and access to toggles */
- qh->dev = u
sb_get_dev (urb->dev)
;
+ qh->dev = u
rb->dev
;
/* using TT? */
switch (urb->dev->speed) {
/* using TT? */
switch (urb->dev->speed) {
@@
-713,7
+721,14
@@
qh_make (
info1 |= maxp << 16;
info2 |= (EHCI_TUNE_MULT_TT << 30);
info1 |= maxp << 16;
info2 |= (EHCI_TUNE_MULT_TT << 30);
- info2 |= urb->dev->ttport << 23;
+
+ /* Some Freescale processors have an erratum in which the
+ * port number in the queue head was 0..N-1 instead of 1..N.
+ */
+ if (ehci_has_fsl_portno_bug(ehci))
+ info2 |= (urb->dev->ttport-1) << 23;
+ else
+ info2 |= urb->dev->ttport << 23;
/* set the address of the TT; for TDI's integrated
* root hub tt, leave it zeroed.
/* set the address of the TT; for TDI's integrated
* root hub tt, leave it zeroed.
@@
-898,12
+913,13
@@
submit_async (
struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
-
int
mem_flags
+
gfp_t
mem_flags
) {
struct ehci_qtd *qtd;
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
) {
struct ehci_qtd *qtd;
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
+ int rc = 0;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
epnum = ep->desc.bEndpointAddress;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
epnum = ep->desc.bEndpointAddress;
@@
-918,21
+934,28
@@
submit_async (
#endif
spin_lock_irqsave (&ehci->lock, flags);
#endif
spin_lock_irqsave (&ehci->lock, flags);
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
+ &ehci_to_hcd(ehci)->flags))) {
+ rc = -ESHUTDOWN;
+ goto done;
+ }
+
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+ if (unlikely(qh == NULL)) {
+ rc = -ENOMEM;
+ goto done;
+ }
/* Control/bulk operations through TTs don't need scheduling,
* the HC and TT handle it when the TT has a buffer ready.
*/
/* Control/bulk operations through TTs don't need scheduling,
* the HC and TT handle it when the TT has a buffer ready.
*/
- if (likely (qh != NULL)) {
- if (likely (qh->qh_state == QH_STATE_IDLE))
- qh_link_async (ehci, qh_get (qh));
- }
+ if (likely (qh->qh_state == QH_STATE_IDLE))
+ qh_link_async (ehci, qh_get (qh));
+ done:
spin_unlock_irqrestore (&ehci->lock, flags);
spin_unlock_irqrestore (&ehci->lock, flags);
- if (unlikely (qh == NULL))
{
+ if (unlikely (qh == NULL))
qtd_list_free (ehci, urb, qtd_list);
qtd_list_free (ehci, urb, qtd_list);
- return -ENOMEM;
- }
- return 0;
+ return rc;
}
/*-------------------------------------------------------------------------*/
}
/*-------------------------------------------------------------------------*/
@@
-999,12
+1022,14
@@
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* stop async schedule right now? */
if (unlikely (qh == ehci->async)) {
/* can't get here without STS_ASS set */
/* stop async schedule right now? */
if (unlikely (qh == ehci->async)) {
/* can't get here without STS_ASS set */
- if (ehci_to_hcd(ehci)->state != HC_STATE_HALT) {
+ if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+ && !ehci->reclaim) {
+ /* ... and CMD_IAAD clear */
writel (cmd & ~CMD_ASE, &ehci->regs->command);
wmb ();
// handshake later, if we need to
writel (cmd & ~CMD_ASE, &ehci->regs->command);
wmb ();
// handshake later, if we need to
+ timer_action_done (ehci, TIMER_ASYNC_OFF);
}
}
- timer_action_done (ehci, TIMER_ASYNC_OFF);
return;
}
return;
}