From 97664a207bc2601a03a300f00e6922038cd5b99c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 6 Jun 2011 14:18:38 +0900 Subject: usb: renesas_usbhs: shrink spin lock area spin lock was very effective while doing 1 packet send/recv on current renesas_usbhs driver. But this lock is enough only - modify packet/pipe link - modify interrpt mask - modify fifo access This patch shrink spin lock area Signed-off-by: Kuninori Morimoto Signed-off-by: Greg Kroah-Hartman diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 0aadcb4..7bf675c 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -204,6 +204,10 @@ void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data); void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data); int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev); + +#define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f) +#define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f) + /* * sysconfig */ diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index e9c4d3d..3cda71e 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -22,7 +22,7 @@ /* * packet info function */ -static int usbhsf_null_handle(struct usbhs_pkt *pkt) +static int usbhsf_null_handle(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pkt->pipe); struct device *dev = usbhs_priv_to_dev(priv); @@ -48,6 +48,10 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct device *dev = usbhs_priv_to_dev(priv); + unsigned long flags; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); if (!handler) { dev_err(dev, "no handler function\n"); @@ -63,14 +67,17 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, pkt->length = len; pkt->zero = zero; pkt->actual = 0; + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ } -void usbhs_pkt_pop(struct usbhs_pkt *pkt) +static void __usbhsf_pkt_del(struct usbhs_pkt *pkt) { list_del_init(&pkt->node); } -struct usbhs_pkt *usbhs_pkt_get(struct usbhs_pipe *pipe) +static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) { if (list_empty(&pipe->list)) return NULL; @@ -78,6 +85,71 @@ struct usbhs_pkt *usbhs_pkt_get(struct usbhs_pipe *pipe) return list_entry(pipe->list.next, struct usbhs_pkt, node); } +struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + unsigned long flags; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + if (!pkt) + pkt = __usbhsf_pkt_get(pipe); + + if (pkt) + __usbhsf_pkt_del(pkt); + + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + return pkt; +} + +int __usbhs_pkt_handler(struct usbhs_pipe *pipe, int type) +{ + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + struct usbhs_pkt *pkt; + struct device *dev = usbhs_priv_to_dev(priv); + int (*func)(struct usbhs_pkt *pkt, int *is_done); + unsigned long flags; + int ret = 0; + int is_done = 0; + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); + + pkt = __usbhsf_pkt_get(pipe); + if (!pkt) + goto __usbhs_pkt_handler_end; + + switch (type) { + case USBHSF_PKT_PREPARE: + func = pkt->handler->prepare; + break; + case USBHSF_PKT_TRY_RUN: + func = pkt->handler->try_run; + break; + default: + dev_err(dev, "unknown pkt hander\n"); + goto __usbhs_pkt_handler_end; + } + + ret = func(pkt, &is_done); + + if (is_done) + __usbhsf_pkt_del(pkt); + +__usbhs_pkt_handler_end: + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ + + if (is_done) + info->done(pkt); + + return ret; +} + /* * irq enable/disable function */ @@ -188,18 +260,17 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe, int write) /* * PIO fifo functions */ -static int usbhsf_try_push(struct usbhs_pkt *pkt) +static int usbhsf_try_push(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); struct device *dev = usbhs_priv_to_dev(priv); void __iomem *addr = priv->base + CFIFO; u8 *buf; int maxp = usbhs_pipe_get_maxpacket(pipe); int total_len; int i, ret, len; - int is_short, is_done; + int is_short; ret = usbhsf_fifo_select(pipe, 1); if (ret < 0) @@ -240,11 +311,11 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt) pkt->actual += total_len; if (pkt->actual < pkt->length) - is_done = 0; /* there are remainder data */ + *is_done = 0; /* there are remainder data */ else if (is_short) - is_done = 1; /* short packet */ + *is_done = 1; /* short packet */ else - is_done = !pkt->zero; /* send zero packet ? */ + *is_done = !pkt->zero; /* send zero packet ? */ /* * pipe/irq handling @@ -252,21 +323,19 @@ static int usbhsf_try_push(struct usbhs_pkt *pkt) if (is_short) usbhsf_send_terminator(pipe); - usbhsf_tx_irq_ctrl(pipe, !is_done); + usbhsf_tx_irq_ctrl(pipe, !*is_done); usbhs_pipe_enable(pipe); dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n", usbhs_pipe_number(pipe), - pkt->length, pkt->actual, is_done, pkt->zero); + pkt->length, pkt->actual, *is_done, pkt->zero); /* * Transmission end */ - if (is_done) { + if (*is_done) { if (usbhs_pipe_is_dcp(pipe)) usbhs_dcp_control_transfer_done(pipe); - - info->done(pkt); } return 0; @@ -286,7 +355,7 @@ struct usbhs_pkt_handle usbhs_fifo_push_handler = { .try_run = usbhsf_try_push, }; -static int usbhsf_prepare_pop(struct usbhs_pkt *pkt) +static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; int ret; @@ -304,7 +373,7 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt) return ret; } -static int usbhsf_try_pop(struct usbhs_pkt *pkt) +static int usbhsf_try_pop(struct usbhs_pkt *pkt, int *is_done) { struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); @@ -316,7 +385,6 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt) int rcv_len, len; int i, ret; int total_len = 0; - int is_done = 0; ret = usbhsf_fifo_select(pipe, 0); if (ret < 0) @@ -367,22 +435,16 @@ static int usbhsf_try_pop(struct usbhs_pkt *pkt) usbhs_fifo_read_end: if ((pkt->actual == pkt->length) || /* receive all data */ - (total_len < maxp)) /* short packet */ - is_done = 1; - - dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n", - usbhs_pipe_number(pipe), - pkt->length, pkt->actual, is_done, pkt->zero); - - if (is_done) { - struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); - + (total_len < maxp)) { /* short packet */ + *is_done = 1; usbhsf_rx_irq_ctrl(pipe, 0); usbhs_pipe_disable(pipe); - - info->done(pkt); } + dev_dbg(dev, " recv %d (%d/ %d/ %d/ %d)\n", + usbhs_pipe_number(pipe), + pkt->length, pkt->actual, *is_done, pkt->zero); + return 0; } @@ -394,15 +456,11 @@ struct usbhs_pkt_handle usbhs_fifo_pop_handler = { /* * handler function */ -static int usbhsf_ctrl_stage_end(struct usbhs_pkt *pkt) +static int usbhsf_ctrl_stage_end(struct usbhs_pkt *pkt, int *is_done) { - struct usbhs_pipe *pipe = pkt->pipe; - struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + usbhs_dcp_control_transfer_done(pkt->pipe); - usbhs_dcp_control_transfer_done(pipe); - - info->done(pkt); + *is_done = 1; return 0; } @@ -419,7 +477,6 @@ static int usbhsf_irq_empty(struct usbhs_priv *priv, struct usbhs_irq_state *irq_state) { struct usbhs_pipe *pipe; - struct usbhs_pkt *pkt; struct device *dev = usbhs_priv_to_dev(priv); int i, ret; @@ -438,8 +495,7 @@ static int usbhsf_irq_empty(struct usbhs_priv *priv, if (!(irq_state->bempsts & (1 << i))) continue; - pkt = usbhs_pkt_get(pipe); - ret = usbhs_pkt_run(pkt); + ret = usbhs_pkt_run(pipe); if (ret < 0) dev_err(dev, "irq_empty run_error %d : %d\n", i, ret); } @@ -451,7 +507,6 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv, struct usbhs_irq_state *irq_state) { struct usbhs_pipe *pipe; - struct usbhs_pkt *pkt; struct device *dev = usbhs_priv_to_dev(priv); int i, ret; @@ -470,8 +525,7 @@ static int usbhsf_irq_ready(struct usbhs_priv *priv, if (!(irq_state->brdysts & (1 << i))) continue; - pkt = usbhs_pkt_get(pipe); - ret = usbhs_pkt_run(pkt); + ret = usbhs_pkt_run(pipe); if (ret < 0) dev_err(dev, "irq_ready run_error %d : %d\n", i, ret); } diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h index eab3258..fcb1ece 100644 --- a/drivers/usb/renesas_usbhs/fifo.h +++ b/drivers/usb/renesas_usbhs/fifo.h @@ -31,8 +31,8 @@ struct usbhs_pkt { }; struct usbhs_pkt_handle { - int (*prepare)(struct usbhs_pkt *pkt); - int (*try_run)(struct usbhs_pkt *pkt); + int (*prepare)(struct usbhs_pkt *pkt, int *is_done); + int (*try_run)(struct usbhs_pkt *pkt, int *is_done); }; /* @@ -44,6 +44,11 @@ void usbhs_fifo_quit(struct usbhs_priv *priv); /* * packet info */ +enum { + USBHSF_PKT_PREPARE, + USBHSF_PKT_TRY_RUN, +}; + extern struct usbhs_pkt_handle usbhs_fifo_push_handler; extern struct usbhs_pkt_handle usbhs_fifo_pop_handler; extern struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler; @@ -52,10 +57,10 @@ void usbhs_pkt_init(struct usbhs_pkt *pkt); void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, struct usbhs_pkt_handle *handler, void *buf, int len, int zero); -void usbhs_pkt_pop(struct usbhs_pkt *pkt); -struct usbhs_pkt *usbhs_pkt_get(struct usbhs_pipe *pipe); +struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); +int __usbhs_pkt_handler(struct usbhs_pipe *pipe, int type); -#define usbhs_pkt_start(p) ((p)->handler->prepare(p)) -#define usbhs_pkt_run(p) ((p)->handler->try_run(p)) +#define usbhs_pkt_start(p) __usbhs_pkt_handler(p, USBHSF_PKT_PREPARE) +#define usbhs_pkt_run(p) __usbhs_pkt_handler(p, USBHSF_PKT_TRY_RUN) #endif /* RENESAS_USB_FIFO_H */ diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 28b2b37..b5a5ba7 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -92,7 +92,6 @@ struct usbhsg_recip_handle { container_of(r, struct usbhsg_request, req) #define usbhsg_ep_to_uep(e) container_of(e, struct usbhsg_uep, ep) -#define usbhsg_gpriv_to_lock(gp) usbhs_priv_to_lock((gp)->mod.priv) #define usbhsg_gpriv_to_dev(gp) usbhs_priv_to_dev((gp)->mod.priv) #define usbhsg_gpriv_to_priv(gp) ((gp)->mod.priv) #define usbhsg_gpriv_to_dcp(gp) ((gp)->uep) @@ -115,35 +114,6 @@ struct usbhsg_recip_handle { #define usbhsg_status_has(gp, b) (gp->status & b) /* - * usbhsg_trylock - * - * This driver don't use spin_try_lock - * to avoid warning of CONFIG_DEBUG_SPINLOCK - */ -static spinlock_t *usbhsg_trylock(struct usbhsg_gpriv *gpriv, - unsigned long *flags) -{ - spinlock_t *lock = usbhsg_gpriv_to_lock(gpriv); - - /* check spin lock status - * to avoid deadlock/nest */ - if (spin_is_locked(lock)) - return NULL; - - spin_lock_irqsave(lock, *flags); - - return lock; -} - -static void usbhsg_unlock(spinlock_t *lock, unsigned long *flags) -{ - if (!lock) - return; - - spin_unlock_irqrestore(lock, *flags); -} - -/* * list push/pop */ static void usbhsg_queue_push(struct usbhsg_uep *uep, @@ -155,9 +125,6 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep, struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); struct usb_request *req = &ureq->req; - /* - ********* assume under spin lock ********* - */ usbhs_pkt_push(pipe, pkt, uep->handler, req->buf, req->length, req->zero); req->actual = 0; @@ -168,44 +135,11 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep, req->length); } -static int usbhsg_queue_start(struct usbhsg_uep *uep) +static void usbhsg_queue_start(struct usbhsg_uep *uep) { - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - struct usbhs_pkt *pkt; - spinlock_t *lock; - unsigned long flags; - int ret = 0; - - /* - * CAUTION [*queue handler*] - * - * This function will be called for start/restart queue operation. - * OTOH the most much worry for USB driver is spinlock nest. - * Specially it are - * - usb_ep_ops :: queue - * - usb_request :: complete - * - * But the caller of this function need not care about spinlock. - * This function is using usbhsg_trylock for it. - * if "is_locked" is 1, this mean this function lock it. - * but if it is 0, this mean it is already under spin lock. - * see also - * CAUTION [*endpoint queue*] - * CAUTION [*request complete*] - */ - - /****************** spin try lock *******************/ - lock = usbhsg_trylock(gpriv, &flags); - - pkt = usbhs_pkt_get(pipe); - if (pkt) - ret = usbhs_pkt_start(pkt); - - usbhsg_unlock(lock, &flags); - /******************** spin unlock ******************/ - return ret; + usbhs_pkt_start(pipe); } static void usbhsg_queue_pop(struct usbhsg_uep *uep, @@ -215,34 +149,9 @@ static void usbhsg_queue_pop(struct usbhsg_uep *uep, struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct device *dev = usbhsg_gpriv_to_dev(gpriv); - struct usbhs_pkt *pkt = usbhsg_ureq_to_pkt(ureq); - - /* - ********* assume under spin lock ********* - */ - - /* - * CAUTION [*request complete*] - * - * There is a possibility not to be called in correct order - * if "complete" is called without spinlock. - * - * So, this function assume it is under spinlock, - * and call usb_request :: complete. - * - * But this "complete" will push next usb_request. - * It mean "usb_ep_ops :: queue" which is using spinlock is called - * under spinlock. - * - * To avoid dead-lock, this driver is using usbhsg_trylock. - * CAUTION [*endpoint queue*] - * CAUTION [*queue handler*] - */ dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe)); - usbhs_pkt_pop(pkt); - ureq->req.status = status; ureq->req.complete(&uep->ep, &ureq->req); @@ -293,8 +202,6 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv, usbhsg_recip_handler_std_control_done(priv, uep, ctrl); - usbhsg_queue_start(uep); - return 0; } @@ -325,7 +232,8 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv, uep = usbhsg_gpriv_to_nth_uep(gpriv, nth); if (!usbhsg_uep_to_pipe(uep)) { dev_err(dev, "wrong recip request\n"); - return -EINVAL; + ret = -EINVAL; + goto usbhsg_recip_run_handle_end; } switch (recip) { @@ -348,10 +256,20 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv, } if (func) { + unsigned long flags; + dev_dbg(dev, "%s (pipe %d :%s)\n", handler->name, nth, msg); + + /******************** spin lock ********************/ + usbhs_lock(priv, flags); ret = func(priv, uep, ctrl); + usbhs_unlock(priv, flags); + /******************** spin unlock ******************/ } +usbhsg_recip_run_handle_end: + usbhsg_queue_start(uep); + return ret; } @@ -445,44 +363,17 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv, * usb_dcp_ops * */ -static int usbhsg_dcp_enable(struct usbhsg_uep *uep) -{ - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); - struct usbhs_pipe *pipe; - - /* - ********* assume under spin lock ********* - */ - - pipe = usbhs_dcp_malloc(priv); - if (!pipe) - return -EIO; - - uep->pipe = pipe; - uep->pipe->mod_private = uep; - - return 0; -} - -#define usbhsg_dcp_disable usbhsg_pipe_disable static int usbhsg_pipe_disable(struct usbhsg_uep *uep) { struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct usbhs_pkt *pkt; - /* - ********* assume under spin lock ********* - */ - usbhs_pipe_disable(pipe); while (1) { - pkt = usbhs_pkt_get(pipe); + pkt = usbhs_pkt_pop(pipe, NULL); if (!pkt) break; - - usbhs_pkt_pop(pkt); } return 0; @@ -509,8 +400,6 @@ static int usbhsg_ep_enable(struct usb_ep *ep, struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct usbhs_pipe *pipe; - spinlock_t *lock; - unsigned long flags; int ret = -EIO; /* @@ -520,9 +409,6 @@ static int usbhsg_ep_enable(struct usb_ep *ep, if (uep->pipe) return 0; - /******************** spin lock ********************/ - lock = usbhsg_trylock(gpriv, &flags); - pipe = usbhs_pipe_malloc(priv, desc); if (pipe) { uep->pipe = pipe; @@ -536,29 +422,14 @@ static int usbhsg_ep_enable(struct usb_ep *ep, ret = 0; } - usbhsg_unlock(lock, &flags); - /******************** spin unlock ******************/ - return ret; } static int usbhsg_ep_disable(struct usb_ep *ep) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - spinlock_t *lock; - unsigned long flags; - int ret; - /******************** spin lock ********************/ - lock = usbhsg_trylock(gpriv, &flags); - - ret = usbhsg_pipe_disable(uep); - - usbhsg_unlock(lock, &flags); - /******************** spin unlock ******************/ - - return ret; + return usbhsg_pipe_disable(uep); } static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep, @@ -591,69 +462,28 @@ static int usbhsg_ep_queue(struct usb_ep *ep, struct usb_request *req, struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); - spinlock_t *lock; - unsigned long flags; - int ret = 0; - - /* - * CAUTION [*endpoint queue*] - * - * This function will be called from usb_request :: complete - * or usb driver timing. - * If this function is called from usb_request :: complete, - * it is already under spinlock on this driver. - * but it is called frm usb driver, this function should call spinlock. - * - * This function is using usbshg_trylock to solve this issue. - * if "is_locked" is 1, this mean this function lock it. - * but if it is 0, this mean it is already under spin lock. - * see also - * CAUTION [*queue handler*] - * CAUTION [*request complete*] - */ - - /******************** spin lock ********************/ - lock = usbhsg_trylock(gpriv, &flags); /* param check */ if (usbhsg_is_not_connected(gpriv) || unlikely(!gpriv->driver) || unlikely(!pipe)) - ret = -ESHUTDOWN; - else - usbhsg_queue_push(uep, ureq); - - usbhsg_unlock(lock, &flags); - /******************** spin unlock ******************/ + return -ESHUTDOWN; + usbhsg_queue_push(uep, ureq); usbhsg_queue_start(uep); - return ret; + return 0; } static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) { struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhsg_request *ureq = usbhsg_req_to_ureq(req); - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - spinlock_t *lock; - unsigned long flags; - - /* - * see - * CAUTION [*queue handler*] - * CAUTION [*endpoint queue*] - * CAUTION [*request complete*] - */ - - /******************** spin lock ********************/ - lock = usbhsg_trylock(gpriv, &flags); + struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); + usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq)); usbhsg_queue_pop(uep, ureq, -ECONNRESET); - usbhsg_unlock(lock, &flags); - /******************** spin unlock ******************/ - return 0; } @@ -662,42 +492,32 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) struct usbhsg_uep *uep = usbhsg_ep_to_uep(ep); struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep); struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct device *dev = usbhsg_gpriv_to_dev(gpriv); - spinlock_t *lock; unsigned long flags; - int ret = -EAGAIN; - /* - * see - * CAUTION [*queue handler*] - * CAUTION [*endpoint queue*] - * CAUTION [*request complete*] - */ - - /******************** spin lock ********************/ - lock = usbhsg_trylock(gpriv, &flags); - if (!usbhs_pkt_get(pipe)) { + usbhsg_pipe_disable(uep); - dev_dbg(dev, "set halt %d (pipe %d)\n", - halt, usbhs_pipe_number(pipe)); + dev_dbg(dev, "set halt %d (pipe %d)\n", + halt, usbhs_pipe_number(pipe)); - if (halt) - usbhs_pipe_stall(pipe); - else - usbhs_pipe_disable(pipe); + /******************** spin lock ********************/ + usbhs_lock(priv, flags); - if (halt && wedge) - usbhsg_status_set(gpriv, USBHSG_STATUS_WEDGE); - else - usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE); + if (halt) + usbhs_pipe_stall(pipe); + else + usbhs_pipe_disable(pipe); - ret = 0; - } + if (halt && wedge) + usbhsg_status_set(gpriv, USBHSG_STATUS_WEDGE); + else + usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE); - usbhsg_unlock(lock, &flags); + usbhs_unlock(priv, flags); /******************** spin unlock ******************/ - return ret; + return 0; } static int usbhsg_ep_set_halt(struct usb_ep *ep, int value) @@ -733,20 +553,26 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); struct usbhs_mod *mod = usbhs_mod_get_current(priv); struct device *dev = usbhs_priv_to_dev(priv); - spinlock_t *lock; unsigned long flags; + int ret = 0; /******************** spin lock ********************/ - lock = usbhsg_trylock(gpriv, &flags); + usbhs_lock(priv, flags); - /* - * enable interrupt and systems if ready - */ usbhsg_status_set(gpriv, status); if (!(usbhsg_status_has(gpriv, USBHSG_STATUS_STARTED) && usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD))) - goto usbhsg_try_start_unlock; + ret = -1; /* not ready */ + + usbhs_unlock(priv, flags); + /******************** spin unlock ********************/ + + if (ret < 0) + return 0; /* not ready is not error */ + /* + * enable interrupt and systems if ready + */ dev_dbg(dev, "start gadget\n"); /* @@ -756,7 +582,10 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) usbhsg_queue_done); usbhs_fifo_init(priv); usbhsg_uep_init(gpriv); - usbhsg_dcp_enable(dcp); + + /* dcp init */ + dcp->pipe = usbhs_dcp_malloc(priv); + dcp->pipe->mod_private = dcp; /* * system config enble @@ -775,10 +604,6 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status) mod->irq_ctrl_stage = usbhsg_irq_ctrl_stage; usbhs_irq_callback_update(priv, mod); -usbhsg_try_start_unlock: - usbhsg_unlock(lock, &flags); - /******************** spin unlock ********************/ - return 0; } @@ -788,20 +613,26 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) struct usbhs_mod *mod = usbhs_mod_get_current(priv); struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv); struct device *dev = usbhs_priv_to_dev(priv); - spinlock_t *lock; unsigned long flags; + int ret = 0; /******************** spin lock ********************/ - lock = usbhsg_trylock(gpriv, &flags); + usbhs_lock(priv, flags); - /* - * disable interrupt and systems if 1st try - */ usbhsg_status_clr(gpriv, status); if (!usbhsg_status_has(gpriv, USBHSG_STATUS_STARTED) && !usbhsg_status_has(gpriv, USBHSG_STATUS_REGISTERD)) - goto usbhsg_try_stop_unlock; + ret = -1; /* already done */ + + usbhs_unlock(priv, flags); + /******************** spin unlock ********************/ + + if (ret < 0) + return 0; /* already done is not error */ + /* + * disable interrupt and systems if 1st try + */ usbhs_fifo_quit(priv); /* disable all irq */ @@ -809,8 +640,6 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) mod->irq_ctrl_stage = NULL; usbhs_irq_callback_update(priv, mod); - usbhsg_dcp_disable(dcp); - gpriv->gadget.speed = USB_SPEED_UNKNOWN; /* disable sys */ @@ -818,8 +647,7 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) usbhs_sys_function_ctrl(priv, 0); usbhs_sys_usb_ctrl(priv, 0); - usbhsg_unlock(lock, &flags); - /******************** spin unlock ********************/ + usbhsg_pipe_disable(dcp); if (gpriv->driver && gpriv->driver->disconnect) @@ -828,11 +656,6 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) dev_dbg(dev, "stop gadget\n"); return 0; - -usbhsg_try_stop_unlock: - usbhsg_unlock(lock, &flags); - - return 0; } /* -- cgit v0.10.2