diff options
7 files changed, 494 insertions, 0 deletions
diff --git a/target/linux/adm5120/patches-2.6.24/910-usb_manage_endpoint_queues.patch b/target/linux/adm5120/patches-2.6.24/910-usb_manage_endpoint_queues.patch new file mode 100644 index 000000000..46b61d637 --- /dev/null +++ b/target/linux/adm5120/patches-2.6.24/910-usb_manage_endpoint_queues.patch @@ -0,0 +1,110 @@ +Index: linux-2.6.24/drivers/usb/host/adm5120-hcd.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-hcd.c ++++ linux-2.6.24/drivers/usb/host/adm5120-hcd.c +@@ -83,8 +83,8 @@ static void admhc_stop(struct usb_hcd *h + /* + * queue up an urb for anything except the root hub + */ +-static int admhc_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *ep, +- struct urb *urb, gfp_t mem_flags) ++static int admhc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, ++ gfp_t mem_flags) + { + struct admhcd *ahcd = hcd_to_admhcd(hcd); + struct ed *ed; +@@ -101,7 +101,7 @@ static int admhc_urb_enqueue(struct usb_ + #endif + + /* every endpoint has an ed, locate and maybe (re)initialize it */ +- ed = ed_get(ahcd, ep, urb->dev, pipe, urb->interval); ++ ed = ed_get(ahcd, urb->ep, urb->dev, pipe, urb->interval); + if (!ed) + return -ENOMEM; + +@@ -161,22 +161,17 @@ static int admhc_urb_enqueue(struct usb_ + goto fail; + } + +- /* in case of unlink-during-submit */ +- spin_lock(&urb->lock); +- if (urb->status != -EINPROGRESS) { +- spin_unlock(&urb->lock); +- urb->hcpriv = urb_priv; +- finish_urb(ahcd, urb); +- ret = 0; ++ ret = usb_hcd_link_urb_to_ep(hcd, urb); ++ if (ret) + goto fail; +- } + + /* schedule the ed if needed */ + if (ed->state == ED_IDLE) { + ret = ed_schedule(ahcd, ed); +- if (ret < 0) +- goto fail0; +- ++ if (ret < 0) { ++ usb_hcd_unlink_urb_from_ep(hcd, urb); ++ goto fail; ++ } + if (ed->type == PIPE_ISOCHRONOUS) { + u16 frame = admhc_frame_no(ahcd); + +@@ -204,8 +199,6 @@ static int admhc_urb_enqueue(struct usb_ + admhc_dump_ed(ahcd, "admhc_urb_enqueue", urb_priv->ed, 1); + #endif + +-fail0: +- spin_unlock(&urb->lock); + fail: + if (ret) + urb_priv_free(ahcd, urb_priv); +@@ -220,18 +213,23 @@ fail: + * asynchronously, and we might be dealing with an urb that's + * partially transferred, or an ED with other urbs being unlinked. + */ +-static int admhc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) ++static int admhc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, ++ int status) + { + struct admhcd *ahcd = hcd_to_admhcd(hcd); + unsigned long flags; ++ int ret; + + spin_lock_irqsave(&ahcd->lock, flags); + + #ifdef ADMHC_VERBOSE_DEBUG + urb_print(ahcd, urb, "DEQUEUE", 1); + #endif +- +- if (HC_IS_RUNNING(hcd->state)) { ++ ret = usb_hcd_check_unlink_urb(hcd, urb, status); ++ if (ret) { ++ /* Do nothing */ ++ ; ++ } else if (HC_IS_RUNNING(hcd->state)) { + struct urb_priv *urb_priv; + + /* Unless an IRQ completed the unlink while it was being +@@ -253,7 +251,7 @@ static int admhc_urb_dequeue(struct usb_ + } + spin_unlock_irqrestore(&ahcd->lock, flags); + +- return 0; ++ return ret; + } + + /*-------------------------------------------------------------------------*/ +Index: linux-2.6.24/drivers/usb/host/adm5120-q.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-q.c ++++ linux-2.6.24/drivers/usb/host/adm5120-q.c +@@ -63,6 +63,7 @@ __acquires(ahcd->lock) + #endif + + /* urb->complete() can reenter this HCD */ ++ usb_hcd_unlink_urb_from_ep(admhcd_to_hcd(ahcd), urb); + spin_unlock(&ahcd->lock); + usb_hcd_giveback_urb(admhcd_to_hcd(ahcd), urb); + spin_lock(&ahcd->lock); diff --git a/target/linux/adm5120/patches-2.6.24/911-usb_centralize_eremoteio_handling.patch b/target/linux/adm5120/patches-2.6.24/911-usb_centralize_eremoteio_handling.patch new file mode 100644 index 000000000..b4e0fb089 --- /dev/null +++ b/target/linux/adm5120/patches-2.6.24/911-usb_centralize_eremoteio_handling.patch @@ -0,0 +1,30 @@ +Index: linux-2.6.24/drivers/usb/host/adm5120-q.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-q.c ++++ linux-2.6.24/drivers/usb/host/adm5120-q.c +@@ -28,25 +28,10 @@ __releases(ahcd->lock) + __acquires(ahcd->lock) + { + urb_priv_free(ahcd, urb->hcpriv); +- urb->hcpriv = NULL; + + spin_lock(&urb->lock); + if (likely(urb->status == -EINPROGRESS)) + urb->status = 0; +- +- /* report short control reads right even though the data TD always +- * has TD_R set. (much simpler, but creates the 1-td limit.) +- */ +- if (unlikely(urb->transfer_flags & URB_SHORT_NOT_OK) +- && unlikely(usb_pipecontrol(urb->pipe)) +- && urb->actual_length < urb->transfer_buffer_length +- && usb_pipein(urb->pipe) +- && urb->status == 0) { +- urb->status = -EREMOTEIO; +-#ifdef ADMHC_VERBOSE_DEBUG +- urb_print(ahcd, urb, "SHORT", usb_pipeout(urb->pipe)); +-#endif +- } + spin_unlock(&urb->lock); + + switch (usb_pipetype(urb->pipe)) { diff --git a/target/linux/adm5120/patches-2.6.24/912-usb_use_urb_unlinked_field.patch b/target/linux/adm5120/patches-2.6.24/912-usb_use_urb_unlinked_field.patch new file mode 100644 index 000000000..a2af8cad7 --- /dev/null +++ b/target/linux/adm5120/patches-2.6.24/912-usb_use_urb_unlinked_field.patch @@ -0,0 +1,23 @@ +Index: linux-2.6.24/drivers/usb/host/adm5120-q.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-q.c ++++ linux-2.6.24/drivers/usb/host/adm5120-q.c +@@ -616,8 +616,7 @@ static int td_done(struct admhcd *ahcd, + + if (cc != TD_CC_NOERROR && cc < TD_CC_HCD0) { + spin_lock(&urb->lock); +- if (urb->status == -EINPROGRESS) +- urb->status = cc_to_error[cc]; ++ urb->status = cc_to_error[cc]; + spin_unlock(&urb->lock); + } + +@@ -787,7 +786,7 @@ rescan_this: + urb = td->urb; + urb_priv = td->urb->hcpriv; + +- if (urb->status == -EINPROGRESS) { ++ if (!urb->unlinked) { + prev = &td->hwNextTD; + continue; + } diff --git a/target/linux/adm5120/patches-2.6.24/913-usb_avoid_donelist_after_an_error.patch b/target/linux/adm5120/patches-2.6.24/913-usb_avoid_donelist_after_an_error.patch new file mode 100644 index 000000000..c6d7d6008 --- /dev/null +++ b/target/linux/adm5120/patches-2.6.24/913-usb_avoid_donelist_after_an_error.patch @@ -0,0 +1,62 @@ +Index: linux-2.6.24/drivers/usb/host/adm5120-q.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-q.c ++++ linux-2.6.24/drivers/usb/host/adm5120-q.c +@@ -641,10 +641,11 @@ static int td_done(struct admhcd *ahcd, + + /*-------------------------------------------------------------------------*/ + +-static inline struct td * ++static inline void + ed_halted(struct admhcd *ahcd, struct td *td, int cc, struct td *rev) + { + struct urb *urb = td->urb; ++ struct urb_priv *urb_priv = urb->hcpriv; + struct ed *ed = td->ed; + struct list_head *tmp = td->td_list.next; + __hc32 toggle = ed->hwHeadP & cpu_to_hc32(ahcd, ED_C); +@@ -657,13 +658,12 @@ ed_halted(struct admhcd *ahcd, struct td + wmb(); + ed->hwHeadP &= ~cpu_to_hc32(ahcd, ED_H); + +- /* put any later tds from this urb onto the donelist, after 'td', +- * order won't matter here: no errors, and nothing was transferred. +- * also patch the ed so it looks as if those tds completed normally. ++ /* Get rid of all later tds from this urb. We don't have ++ * to be careful: no errors and nothing was transferred. ++ * Also patch the ed so it looks as if those tds completed normally. + */ + while (tmp != &ed->td_list) { + struct td *next; +- __hc32 info; + + next = list_entry(tmp, struct td, td_list); + tmp = next->td_list.next; +@@ -678,16 +678,8 @@ ed_halted(struct admhcd *ahcd, struct td + * then we need to leave the control STATUS packet queued + * and clear ED_SKIP. + */ +- info = next->hwINFO; +-#if 0 /* FIXME */ +- info |= cpu_to_hc32(ahcd, TD_DONE); +-#endif +- info &= ~cpu_to_hc32(ahcd, TD_CC); +- next->hwINFO = info; +- +- next->next_dl_td = rev; +- rev = next; +- ++ list_del(&next->td_list); ++ urb_priv->td_cnt++; + ed->hwHeadP = next->hwNextTD | toggle; + } + +@@ -713,8 +705,6 @@ ed_halted(struct admhcd *ahcd, struct td + hc32_to_cpu(ahcd, td->hwINFO), + cc, cc_to_error [cc]); + } +- +- return rev; + } + + /*-------------------------------------------------------------------------*/ diff --git a/target/linux/adm5120/patches-2.6.24/914-usb_reorganize_urb_status_use.patch b/target/linux/adm5120/patches-2.6.24/914-usb_reorganize_urb_status_use.patch new file mode 100644 index 000000000..79a53d801 --- /dev/null +++ b/target/linux/adm5120/patches-2.6.24/914-usb_reorganize_urb_status_use.patch @@ -0,0 +1,242 @@ +Index: linux-2.6.24/drivers/usb/host/adm5120-dbg.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-dbg.c ++++ linux-2.6.24/drivers/usb/host/adm5120-dbg.c +@@ -82,7 +82,7 @@ static inline char *td_togglestring(u32 + * small: 0) header + data packets 1) just header + */ + static void __attribute__((unused)) +-urb_print(struct admhcd *ahcd, struct urb *urb, char *str, int small) ++urb_print(struct admhcd *ahcd, struct urb *urb, char *str, int small, int status) + { + unsigned int pipe = urb->pipe; + +@@ -92,7 +92,7 @@ urb_print(struct admhcd *ahcd, struct ur + } + + #ifndef ADMHC_VERBOSE_DEBUG +- if (urb->status != 0) ++ if (status != 0) + #endif + admhc_dbg(ahcd, "URB-%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d " + "stat=%d\n", +@@ -105,7 +105,7 @@ urb_print(struct admhcd *ahcd, struct ur + urb->transfer_flags, + urb->actual_length, + urb->transfer_buffer_length, +- urb->status); ++ status); + + #ifdef ADMHC_VERBOSE_DEBUG + if (!small) { +@@ -125,7 +125,7 @@ urb_print(struct admhcd *ahcd, struct ur + urb->transfer_buffer_length: urb->actual_length; + for (i = 0; i < 16 && i < len; i++) + printk(" %02x", ((__u8 *)urb->transfer_buffer)[i]); +- printk("%s stat:%d\n", i < len? "...": "", urb->status); ++ printk("%s stat:%d\n", i < len? "...": "", status); + } + } + #endif /* ADMHC_VERBOSE_DEBUG */ +Index: linux-2.6.24/drivers/usb/host/adm5120-hcd.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-hcd.c ++++ linux-2.6.24/drivers/usb/host/adm5120-hcd.c +@@ -96,7 +96,7 @@ static int admhc_urb_enqueue(struct usb_ + + #ifdef ADMHC_VERBOSE_DEBUG + spin_lock_irqsave(&ahcd->lock, flags); +- urb_print(ahcd, urb, "ENQEUE", usb_pipein(pipe)); ++ urb_print(ahcd, urb, "ENQEUE", usb_pipein(pipe), -EINPROGRESS); + spin_unlock_irqrestore(&ahcd->lock, flags); + #endif + +@@ -208,8 +208,8 @@ fail: + } + + /* +- * decouple the URB from the HC queues (TDs, urb_priv); it's +- * already marked using urb->status. reporting is always done ++ * decouple the URB from the HC queues (TDs, urb_priv); ++ * reporting is always done + * asynchronously, and we might be dealing with an urb that's + * partially transferred, or an ED with other urbs being unlinked. + */ +@@ -223,7 +223,7 @@ static int admhc_urb_dequeue(struct usb_ + spin_lock_irqsave(&ahcd->lock, flags); + + #ifdef ADMHC_VERBOSE_DEBUG +- urb_print(ahcd, urb, "DEQUEUE", 1); ++ urb_print(ahcd, urb, "DEQUEUE", 1, status); + #endif + ret = usb_hcd_check_unlink_urb(hcd, urb, status); + if (ret) { +@@ -247,7 +247,7 @@ static int admhc_urb_dequeue(struct usb_ + * any more ... just clean up every urb's memory. + */ + if (urb->hcpriv) +- finish_urb(ahcd, urb); ++ finish_urb(ahcd, urb, status); + } + spin_unlock_irqrestore(&ahcd->lock, flags); + +Index: linux-2.6.24/drivers/usb/host/adm5120-pm.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-pm.c ++++ linux-2.6.24/drivers/usb/host/adm5120-pm.c +@@ -383,9 +383,8 @@ static int admhc_restart(struct admhcd * + ed, ed->state); + } + +- spin_lock(&urb->lock); +- urb->status = -ESHUTDOWN; +- spin_unlock(&urb->lock); ++ if (!urb->unlinked) ++ urb->unlinked = -ESHUTDOWN; + } + finish_unlinks(ahcd, 0); + spin_unlock_irq(&ahcd->lock); +Index: linux-2.6.24/drivers/usb/host/adm5120-q.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-q.c ++++ linux-2.6.24/drivers/usb/host/adm5120-q.c +@@ -23,16 +23,14 @@ + * PRECONDITION: ahcd lock held, irqs blocked. + */ + static void +-finish_urb(struct admhcd *ahcd, struct urb *urb) ++finish_urb(struct admhcd *ahcd, struct urb *urb, int status) + __releases(ahcd->lock) + __acquires(ahcd->lock) + { + urb_priv_free(ahcd, urb->hcpriv); + +- spin_lock(&urb->lock); +- if (likely(urb->status == -EINPROGRESS)) +- urb->status = 0; +- spin_unlock(&urb->lock); ++ if (likely(status == -EINPROGRESS)) ++ status = 0; + + switch (usb_pipetype(urb->pipe)) { + case PIPE_ISOCHRONOUS: +@@ -44,12 +42,13 @@ __acquires(ahcd->lock) + } + + #ifdef ADMHC_VERBOSE_DEBUG +- urb_print(ahcd, urb, "RET", usb_pipeout (urb->pipe)); ++ urb_print(ahcd, urb, "RET", usb_pipeout (urb->pipe), status); + #endif + + /* urb->complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(admhcd_to_hcd(ahcd), urb); + spin_unlock(&ahcd->lock); ++ urb->status = status; + usb_hcd_giveback_urb(admhcd_to_hcd(ahcd), urb); + spin_lock(&ahcd->lock); + } +@@ -557,9 +556,7 @@ static void td_submit_urb(struct admhcd + * Done List handling functions + *-------------------------------------------------------------------------*/ + +-/* calculate transfer length/status and update the urb +- * PRECONDITION: irqsafe (only for urb->status locking) +- */ ++/* calculate transfer length/status and update the urb */ + static int td_done(struct admhcd *ahcd, struct urb *urb, struct td *td) + { + struct urb_priv *urb_priv = urb->hcpriv; +@@ -568,6 +565,7 @@ static int td_done(struct admhcd *ahcd, + u32 tdDBP; + int type = usb_pipetype(urb->pipe); + int cc; ++ int status = -EINPROGRESS; + + info = hc32_to_cpup(ahcd, &td->hwINFO); + tdDBP = hc32_to_cpup(ahcd, &td->hwDBP); +@@ -582,10 +580,9 @@ static int td_done(struct admhcd *ahcd, + /* NOTE: assumes FC in tdINFO == 0, and that + * only the first of 0..MAXPSW psws is used. + */ +-#if 0 +- if (tdINFO & TD_CC) /* hc didn't touch? */ +- return; +-#endif ++ if (info & TD_CC) /* hc didn't touch? */ ++ return status; ++ + if (usb_pipeout(urb->pipe)) + dlen = urb->iso_frame_desc[td->index].length; + else { +@@ -614,11 +611,9 @@ static int td_done(struct admhcd *ahcd, + && !(urb->transfer_flags & URB_SHORT_NOT_OK)) + cc = TD_CC_NOERROR; + +- if (cc != TD_CC_NOERROR && cc < TD_CC_HCD0) { +- spin_lock(&urb->lock); +- urb->status = cc_to_error[cc]; +- spin_unlock(&urb->lock); +- } ++ if (cc != TD_CC_NOERROR && cc < TD_CC_HCD0) ++ status = cc_to_error[cc]; ++ + + /* count all non-empty packets except control SETUP packet */ + if ((type != PIPE_CONTROL || td->index != 0) && tdDBP != 0) { +@@ -636,7 +631,7 @@ static int td_done(struct admhcd *ahcd, + list_del(&td->td_list); + urb_priv->td_idx++; + +- return cc; ++ return status; + } + + /*-------------------------------------------------------------------------*/ +@@ -771,6 +766,7 @@ rescan_this: + struct urb *urb; + struct urb_priv *urb_priv; + __hc32 savebits; ++ int status; + + td = list_entry(entry, struct td, td_list); + urb = td->urb; +@@ -792,12 +788,12 @@ rescan_this: + #ifdef ADMHC_VERBOSE_DEBUG + urb_print(ahcd, urb, "PARTIAL", 0); + #endif +- td_done(ahcd, urb, td); ++ status = td_done(ahcd, urb, td); + + /* if URB is done, clean up */ + if (urb_priv->td_idx == urb_priv->td_cnt) { + modified = completed = 1; +- finish_urb(ahcd, urb); ++ finish_urb(ahcd, urb, status); + } + } + if (completed && !list_empty(&ed->td_list)) +@@ -895,13 +891,13 @@ static void ed_update(struct admhcd *ahc + struct td *td = list_entry(entry, struct td, td_list); + struct urb *urb = td->urb; + struct urb_priv *urb_priv = urb->hcpriv; +- int cc; ++ int status; + + if (hc32_to_cpup(ahcd, &td->hwINFO) & TD_OWN) + break; + + /* update URB's length and status from TD */ +- cc = td_done(ahcd, urb, td); ++ status = td_done(ahcd, urb, td); + if (is_ed_halted(ahcd, ed) && is_td_halted(ahcd, ed, td)) + ed_unhalt(ahcd, ed, urb); + +@@ -910,7 +906,7 @@ static void ed_update(struct admhcd *ahc + + /* If all this urb's TDs are done, call complete() */ + if (urb_priv->td_idx == urb_priv->td_cnt) +- finish_urb(ahcd, urb); ++ finish_urb(ahcd, urb, status); + + /* clean schedule: unlink EDs that are no longer busy */ + if (list_empty(&ed->td_list)) { diff --git a/target/linux/adm5120/patches-2.6.24/915-usb_eliminate_urb_status.patch b/target/linux/adm5120/patches-2.6.24/915-usb_eliminate_urb_status.patch new file mode 100644 index 000000000..291b1ade5 --- /dev/null +++ b/target/linux/adm5120/patches-2.6.24/915-usb_eliminate_urb_status.patch @@ -0,0 +1,14 @@ +Index: linux-2.6.24/drivers/usb/host/adm5120-q.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-q.c ++++ linux-2.6.24/drivers/usb/host/adm5120-q.c +@@ -48,8 +48,7 @@ __acquires(ahcd->lock) + /* urb->complete() can reenter this HCD */ + usb_hcd_unlink_urb_from_ep(admhcd_to_hcd(ahcd), urb); + spin_unlock(&ahcd->lock); +- urb->status = status; +- usb_hcd_giveback_urb(admhcd_to_hcd(ahcd), urb); ++ usb_hcd_giveback_urb(admhcd_to_hcd(ahcd), urb, status); + spin_lock(&ahcd->lock); + } + diff --git a/target/linux/adm5120/patches-2.6.24/916-usb_bump_version_number.patch b/target/linux/adm5120/patches-2.6.24/916-usb_bump_version_number.patch new file mode 100644 index 000000000..312c1f322 --- /dev/null +++ b/target/linux/adm5120/patches-2.6.24/916-usb_bump_version_number.patch @@ -0,0 +1,13 @@ +Index: linux-2.6.24/drivers/usb/host/adm5120-hcd.c +=================================================================== +--- linux-2.6.24.orig/drivers/usb/host/adm5120-hcd.c ++++ linux-2.6.24/drivers/usb/host/adm5120-hcd.c +@@ -45,7 +45,7 @@ + #include "../core/hcd.h" + #include "../core/hub.h" + +-#define DRIVER_VERSION "0.16.3" ++#define DRIVER_VERSION "0.24.0" + #define DRIVER_AUTHOR "Gabor Juhos <juhosg at openwrt.org>" + #define DRIVER_DESC "ADMtek USB 1.1 Host Controller Driver" + |