* [PATCH v2] usb/fsl_udc: fix dequeuing a request in progress
@ 2011-11-23 12:12 Li Yang
2011-11-24 1:56 ` Peter Chen
2011-11-24 9:48 ` Felipe Balbi
0 siblings, 2 replies; 3+ messages in thread
From: Li Yang @ 2011-11-23 12:12 UTC (permalink / raw)
To: balbi, gregkh; +Cc: linux-usb, linuxppc-dev, Peter Chen
The original implementation of dequeuing a request in progress
is not correct. Change to use a correct process and also clean
up the related functions a little bit.
Signed-off-by: Li Yang <leoli@freescale.com>
Cc: Peter Chen <peter.chen@freescale.com>
---
drivers/usb/gadget/fsl_udc_core.c | 68 +++++++++++++++++-------------------
drivers/usb/gadget/fsl_usb2_udc.h | 10 +++++
2 files changed, 42 insertions(+), 36 deletions(-)
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index b2c44e1..cc704dc 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -696,12 +696,31 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
-/*-------------------------------------------------------------------------*/
+/* Actually add a dTD chain to an empty dQH and let go */
+static void fsl_prime_ep(struct fsl_ep *ep, struct ep_td_struct *td)
+{
+ struct ep_queue_head *qh = get_qh_by_ep(ep);
+
+ /* Write dQH next pointer and terminate bit to 0 */
+ qh->next_dtd_ptr = cpu_to_hc32(td->td_dma
+ & EP_QUEUE_HEAD_NEXT_POINTER_MASK);
+
+ /* Clear active and halt bit */
+ qh->size_ioc_int_sts &= cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
+ | EP_QUEUE_HEAD_STATUS_HALT));
+
+ /* Ensure that updates to the QH will occur before priming. */
+ wmb();
+
+ /* Prime endpoint by writing correct bit to ENDPTPRIME */
+ fsl_writel(ep_is_in(ep) ? (1 << (ep_index(ep) + 16))
+ : (1 << (ep_index(ep))), &dr_regs->endpointprime);
+}
+
+/* Add dTD chain to the dQH of an EP */
static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
{
- int i = ep_index(ep) * 2 + ep_is_in(ep);
u32 temp, bitmask, tmp_stat;
- struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
/* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr);
VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */
@@ -719,7 +738,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
/* Read prime bit, if 1 goto done */
if (fsl_readl(&dr_regs->endpointprime) & bitmask)
- goto out;
+ return;
do {
/* Set ATDTW bit in USBCMD */
@@ -736,28 +755,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd);
if (tmp_stat)
- goto out;
+ return;
}
- /* Write dQH next pointer and terminate bit to 0 */
- temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
- dQH->next_dtd_ptr = cpu_to_hc32(temp);
-
- /* Clear active and halt bit */
- temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
- | EP_QUEUE_HEAD_STATUS_HALT));
- dQH->size_ioc_int_sts &= temp;
-
- /* Ensure that updates to the QH will occur before priming. */
- wmb();
-
- /* Prime endpoint by writing 1 to ENDPTPRIME */
- temp = ep_is_in(ep)
- ? (1 << (ep_index(ep) + 16))
- : (1 << (ep_index(ep)));
- fsl_writel(temp, &dr_regs->endpointprime);
-out:
- return;
+ fsl_prime_ep(ep, req->head);
}
/* Fill in the dTD structure
@@ -973,25 +974,20 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
/* The request isn't the last request in this ep queue */
if (req->queue.next != &ep->queue) {
- struct ep_queue_head *qh;
struct fsl_req *next_req;
- qh = ep->qh;
next_req = list_entry(req->queue.next, struct fsl_req,
queue);
- /* Point the QH to the first TD of next request */
- fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr);
+ /* prime with dTD of next request */
+ fsl_prime_ep(ep, next_req->head);
}
-
- /* The request hasn't been processed, patch up the TD chain */
+ /* The request hasn't been processed, patch up the TD chain */
} else {
struct fsl_req *prev_req;
prev_req = list_entry(req->queue.prev, struct fsl_req, queue);
- fsl_writel(fsl_readl(&req->tail->next_td_ptr),
- &prev_req->tail->next_td_ptr);
-
+ prev_req->tail->next_td_ptr = req->tail->next_td_ptr;
}
done(ep, req, -ECONNRESET);
@@ -1068,7 +1064,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
struct fsl_udc *udc;
int size = 0;
u32 bitmask;
- struct ep_queue_head *d_qh;
+ struct ep_queue_head *qh;
ep = container_of(_ep, struct fsl_ep, ep);
if (!_ep || (!ep->desc && ep_index(ep) != 0))
@@ -1079,13 +1075,13 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
- d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)];
+ qh = get_qh_by_ep(ep);
bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
(1 << (ep_index(ep)));
if (fsl_readl(&dr_regs->endptstatus) & bitmask)
- size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE)
+ size = (qh->size_ioc_int_sts & DTD_PACKET_SIZE)
>> DTD_LENGTH_BIT_POS;
pr_debug("%s %u\n", __func__, size);
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index 1d51be8..f781f5d 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -569,6 +569,16 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
* 2 + ((windex & USB_DIR_IN) ? 1 : 0))
#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP))
+static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep)
+{
+ /* we only have one ep0 structure but two queue heads */
+ if (ep_index(ep) != 0)
+ return ep->qh;
+ else
+ return &ep->udc->ep_qh[(ep->udc->ep0_dir ==
+ USB_DIR_IN) ? 1 : 0];
+}
+
struct platform_device;
#ifdef CONFIG_ARCH_MXC
int fsl_udc_clk_init(struct platform_device *pdev);
--
1.5.4.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH v2] usb/fsl_udc: fix dequeuing a request in progress
2011-11-23 12:12 [PATCH v2] usb/fsl_udc: fix dequeuing a request in progress Li Yang
@ 2011-11-24 1:56 ` Peter Chen
2011-11-24 9:48 ` Felipe Balbi
1 sibling, 0 replies; 3+ messages in thread
From: Peter Chen @ 2011-11-24 1:56 UTC (permalink / raw)
To: Li Yang; +Cc: gregkh, linuxppc-dev, linux-usb, balbi
On Wed, Nov 23, 2011 at 08:12:56PM +0800, Li Yang wrote:
> The original implementation of dequeuing a request in progress
> is not correct. Change to use a correct process and also clean
> up the related functions a little bit.
>
> Signed-off-by: Li Yang <leoli@freescale.com>
> Cc: Peter Chen <peter.chen@freescale.com>
> ---
> drivers/usb/gadget/fsl_udc_core.c | 68 +++++++++++++++++-------------------
> drivers/usb/gadget/fsl_usb2_udc.h | 10 +++++
> 2 files changed, 42 insertions(+), 36 deletions(-)
>
> diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
> index b2c44e1..cc704dc 100644
> --- a/drivers/usb/gadget/fsl_udc_core.c
> +++ b/drivers/usb/gadget/fsl_udc_core.c
> @@ -696,12 +696,31 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
> kfree(req);
> }
>
> -/*-------------------------------------------------------------------------*/
> +/* Actually add a dTD chain to an empty dQH and let go */
> +static void fsl_prime_ep(struct fsl_ep *ep, struct ep_td_struct *td)
> +{
> + struct ep_queue_head *qh = get_qh_by_ep(ep);
> +
> + /* Write dQH next pointer and terminate bit to 0 */
> + qh->next_dtd_ptr = cpu_to_hc32(td->td_dma
> + & EP_QUEUE_HEAD_NEXT_POINTER_MASK);
> +
> + /* Clear active and halt bit */
> + qh->size_ioc_int_sts &= cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
> + | EP_QUEUE_HEAD_STATUS_HALT));
> +
> + /* Ensure that updates to the QH will occur before priming. */
> + wmb();
> +
> + /* Prime endpoint by writing correct bit to ENDPTPRIME */
> + fsl_writel(ep_is_in(ep) ? (1 << (ep_index(ep) + 16))
> + : (1 << (ep_index(ep))), &dr_regs->endpointprime);
> +}
> +
> +/* Add dTD chain to the dQH of an EP */
> static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
> {
> - int i = ep_index(ep) * 2 + ep_is_in(ep);
> u32 temp, bitmask, tmp_stat;
> - struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
>
> /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr);
> VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */
> @@ -719,7 +738,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
> cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK);
> /* Read prime bit, if 1 goto done */
> if (fsl_readl(&dr_regs->endpointprime) & bitmask)
> - goto out;
> + return;
>
> do {
> /* Set ATDTW bit in USBCMD */
> @@ -736,28 +755,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
> fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd);
>
> if (tmp_stat)
> - goto out;
> + return;
> }
>
> - /* Write dQH next pointer and terminate bit to 0 */
> - temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
> - dQH->next_dtd_ptr = cpu_to_hc32(temp);
> -
> - /* Clear active and halt bit */
> - temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE
> - | EP_QUEUE_HEAD_STATUS_HALT));
> - dQH->size_ioc_int_sts &= temp;
> -
> - /* Ensure that updates to the QH will occur before priming. */
> - wmb();
> -
> - /* Prime endpoint by writing 1 to ENDPTPRIME */
> - temp = ep_is_in(ep)
> - ? (1 << (ep_index(ep) + 16))
> - : (1 << (ep_index(ep)));
> - fsl_writel(temp, &dr_regs->endpointprime);
> -out:
> - return;
> + fsl_prime_ep(ep, req->head);
> }
>
> /* Fill in the dTD structure
> @@ -973,25 +974,20 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
>
> /* The request isn't the last request in this ep queue */
> if (req->queue.next != &ep->queue) {
> - struct ep_queue_head *qh;
> struct fsl_req *next_req;
>
> - qh = ep->qh;
> next_req = list_entry(req->queue.next, struct fsl_req,
> queue);
>
> - /* Point the QH to the first TD of next request */
> - fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr);
> + /* prime with dTD of next request */
> + fsl_prime_ep(ep, next_req->head);
> }
> -
> - /* The request hasn't been processed, patch up the TD chain */
> + /* The request hasn't been processed, patch up the TD chain */
> } else {
> struct fsl_req *prev_req;
>
> prev_req = list_entry(req->queue.prev, struct fsl_req, queue);
> - fsl_writel(fsl_readl(&req->tail->next_td_ptr),
> - &prev_req->tail->next_td_ptr);
> -
> + prev_req->tail->next_td_ptr = req->tail->next_td_ptr;
> }
>
> done(ep, req, -ECONNRESET);
> @@ -1068,7 +1064,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
> struct fsl_udc *udc;
> int size = 0;
> u32 bitmask;
> - struct ep_queue_head *d_qh;
> + struct ep_queue_head *qh;
>
> ep = container_of(_ep, struct fsl_ep, ep);
> if (!_ep || (!ep->desc && ep_index(ep) != 0))
> @@ -1079,13 +1075,13 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep)
> if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
> return -ESHUTDOWN;
>
> - d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)];
> + qh = get_qh_by_ep(ep);
>
> bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
> (1 << (ep_index(ep)));
>
> if (fsl_readl(&dr_regs->endptstatus) & bitmask)
> - size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE)
> + size = (qh->size_ioc_int_sts & DTD_PACKET_SIZE)
> >> DTD_LENGTH_BIT_POS;
>
> pr_debug("%s %u\n", __func__, size);
> diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
> index 1d51be8..f781f5d 100644
> --- a/drivers/usb/gadget/fsl_usb2_udc.h
> +++ b/drivers/usb/gadget/fsl_usb2_udc.h
> @@ -569,6 +569,16 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
> * 2 + ((windex & USB_DIR_IN) ? 1 : 0))
> #define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP))
>
> +static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep)
> +{
> + /* we only have one ep0 structure but two queue heads */
> + if (ep_index(ep) != 0)
> + return ep->qh;
> + else
> + return &ep->udc->ep_qh[(ep->udc->ep0_dir ==
> + USB_DIR_IN) ? 1 : 0];
> +}
> +
> struct platform_device;
> #ifdef CONFIG_ARCH_MXC
> int fsl_udc_clk_init(struct platform_device *pdev);
> --
> 1.5.4.3
>
Testing this patch at i.MX51 BBG, and it is OK.
Acked-by: Peter Chen <peter.chen@freescale.com>
--
Best Regards,
Peter Chen
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH v2] usb/fsl_udc: fix dequeuing a request in progress
2011-11-23 12:12 [PATCH v2] usb/fsl_udc: fix dequeuing a request in progress Li Yang
2011-11-24 1:56 ` Peter Chen
@ 2011-11-24 9:48 ` Felipe Balbi
1 sibling, 0 replies; 3+ messages in thread
From: Felipe Balbi @ 2011-11-24 9:48 UTC (permalink / raw)
To: Li Yang; +Cc: gregkh, linuxppc-dev, linux-usb, balbi, Peter Chen
[-- Attachment #1: Type: text/plain, Size: 363 bytes --]
On Wed, Nov 23, 2011 at 08:12:56PM +0800, Li Yang wrote:
> The original implementation of dequeuing a request in progress
> is not correct. Change to use a correct process and also clean
> up the related functions a little bit.
>
> Signed-off-by: Li Yang <leoli@freescale.com>
> Cc: Peter Chen <peter.chen@freescale.com>
applied, thanks
--
balbi
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-11-24 9:49 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-23 12:12 [PATCH v2] usb/fsl_udc: fix dequeuing a request in progress Li Yang
2011-11-24 1:56 ` Peter Chen
2011-11-24 9:48 ` Felipe Balbi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).