Skip to content

Commit

Permalink
Merge pull request #255 from P33M/rpi-3.6.y
Browse files Browse the repository at this point in the history
dwc_otg: implement tasklet for returning URBs to usbcore hcd layer
  • Loading branch information
popcornmix committed Mar 24, 2013
2 parents 7f26025 + c4564d4 commit 79ec5aa
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 17 deletions.
5 changes: 5 additions & 0 deletions drivers/usb/host/dwc_common_port/dwc_common_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,11 @@ void DWC_TASK_SCHEDULE(dwc_tasklet_t *task)
tasklet_schedule(&task->t);
}

void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task)
{
tasklet_hi_schedule(&task->t);
}


/* workqueues
- run in process context (can sleep)
Expand Down
14 changes: 7 additions & 7 deletions drivers/usb/host/dwc_common_port/dwc_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,17 +384,17 @@ struct { \
#define DWC_TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define DWC_TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
(DWC_TAILQ_FIRST(head) == DWC_TAILQ_END(head))

#define DWC_TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
for ((var) = DWC_TAILQ_FIRST(head); \
(var) != DWC_TAILQ_END(head); \
(var) = DWC_TAILQ_NEXT(var, field))

#define DWC_TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
for ((var) = DWC_TAILQ_LAST(head, headname); \
(var) != DWC_TAILQ_END(head); \
(var) = DWC_TAILQ_PREV(var, headname, field))

/*
* Tail queue functions.
Expand Down
2 changes: 2 additions & 0 deletions drivers/usb/host/dwc_common_port/dwc_os.h
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,8 @@ extern void DWC_TASK_FREE(dwc_tasklet_t *task);
extern void DWC_TASK_SCHEDULE(dwc_tasklet_t *task);
#define dwc_task_schedule DWC_TASK_SCHEDULE

extern void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task);
#define dwc_task_hi_schedule DWC_TASK_HI_SCHEDULE

/** @name Timer
*
Expand Down
34 changes: 33 additions & 1 deletion drivers/usb/host/dwc_otg/dwc_otg_hcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
* header file.
*/

#include <linux/usb.h>
#include <linux/usb/hcd.h>

#include "dwc_otg_hcd.h"
#include "dwc_otg_regs.h"

Expand Down Expand Up @@ -694,6 +697,31 @@ static void reset_tasklet_func(void *data)
dwc_otg_hcd->flags.b.port_reset_change = 1;
}

static void completion_tasklet_func(void *ptr)
{
dwc_otg_hcd_t *hcd = (dwc_otg_hcd_t *) ptr;
struct urb *urb;
urb_tq_entry_t *item;
dwc_irqflags_t flags;

DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
while (!DWC_TAILQ_EMPTY(&hcd->completed_urb_list)) {
item = DWC_TAILQ_FIRST(&hcd->completed_urb_list);
urb = item->urb;
DWC_TAILQ_REMOVE(&hcd->completed_urb_list, item,
urb_tq_entries);
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
DWC_FREE(item);

usb_hcd_unlink_urb_from_ep(hcd->priv, urb);
usb_hcd_giveback_urb(hcd->priv, urb, urb->status);

DWC_SPINLOCK_IRQSAVE(hcd->lock, &flags);
}
DWC_SPINUNLOCK_IRQRESTORE(hcd->lock, flags);
return;
}

static void qh_list_free(dwc_otg_hcd_t * hcd, dwc_list_link_t * qh_list)
{
dwc_list_link_t *item;
Expand Down Expand Up @@ -833,6 +861,7 @@ static void dwc_otg_hcd_free(dwc_otg_hcd_t * dwc_otg_hcd)

DWC_TIMER_FREE(dwc_otg_hcd->conn_timer);
DWC_TASK_FREE(dwc_otg_hcd->reset_tasklet);
DWC_TASK_FREE(dwc_otg_hcd->completion_tasklet);

#ifdef DWC_DEV_SRPCAP
if (dwc_otg_hcd->core_if->power_down == 2 &&
Expand Down Expand Up @@ -877,7 +906,7 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)
DWC_LIST_INIT(&hcd->periodic_sched_ready);
DWC_LIST_INIT(&hcd->periodic_sched_assigned);
DWC_LIST_INIT(&hcd->periodic_sched_queued);

DWC_TAILQ_INIT(&hcd->completed_urb_list);
/*
* Create a host channel descriptor for each host channel implemented
* in the controller. Initialize the channel descriptor array.
Expand Down Expand Up @@ -915,6 +944,9 @@ int dwc_otg_hcd_init(dwc_otg_hcd_t * hcd, dwc_otg_core_if_t * core_if)

/* Initialize reset tasklet. */
hcd->reset_tasklet = DWC_TASK_ALLOC("reset_tasklet", reset_tasklet_func, hcd);

hcd->completion_tasklet = DWC_TASK_ALLOC("completion_tasklet",
completion_tasklet_func, hcd);
#ifdef DWC_DEV_SRPCAP
if (hcd->core_if->power_down == 2) {
/* Initialize Power on timer for Host power up in case hibernation */
Expand Down
10 changes: 10 additions & 0 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,13 @@ typedef struct dwc_otg_qh {

DWC_CIRCLEQ_HEAD(hc_list, dwc_hc);

typedef struct urb_tq_entry {
struct urb *urb;
DWC_TAILQ_ENTRY(urb_tq_entry) urb_tq_entries;
} urb_tq_entry_t;

DWC_TAILQ_HEAD(urb_list, urb_tq_entry);

/**
* This structure holds the state of the HCD, including the non-periodic and
* periodic schedules.
Expand Down Expand Up @@ -551,6 +558,9 @@ struct dwc_otg_hcd {
/* Tasket to do a reset */
dwc_tasklet_t *reset_tasklet;

dwc_tasklet_t *completion_tasklet;
struct urb_list completed_urb_list;

/* */
dwc_spinlock_t *lock;
dwc_spinlock_t *channel_lock;
Expand Down
25 changes: 16 additions & 9 deletions drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
dwc_otg_hcd_urb_t * dwc_otg_urb, int32_t status)
{
struct urb *urb = (struct urb *)urb_handle;

urb_tq_entry_t *new_entry;
if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
__func__, urb, usb_pipedevice(urb->pipe),
Expand All @@ -285,7 +285,7 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
}
}
}

new_entry = DWC_ALLOC_ATOMIC(sizeof(urb_tq_entry_t));
urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
/* Convert status value. */
switch (status) {
Expand Down Expand Up @@ -348,18 +348,25 @@ static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
}

DWC_FREE(dwc_otg_urb);

if (!new_entry) {
DWC_ERROR("dwc_otg_hcd: complete: cannot allocate URB TQ entry\n");
urb->status = -EPROTO;
/* don't schedule the tasklet -
* directly return the packet here with error. */
#if USB_URB_EP_LINKING
usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
usb_hcd_unlink_urb_from_ep(dwc_otg_hcd_to_hcd(hcd), urb);
#endif
DWC_SPINUNLOCK(hcd->lock);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb);
#else
usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, urb->status);
#endif
DWC_SPINLOCK(hcd->lock);

} else {
new_entry->urb = urb;
DWC_TAILQ_INSERT_TAIL(&hcd->completed_urb_list, new_entry,
urb_tq_entries);
DWC_TASK_HI_SCHEDULE(hcd->completion_tasklet);
}
return 0;
}

Expand Down

0 comments on commit 79ec5aa

Please sign in to comment.