usb: gadget: mv_udc: rewrite queue_dtd according to spec

Rewrite function queue_dtd according to ChipIdea's reference manual.
Remove all unnecessary logic, it will enhance the performance.

Signed-off-by: Neil Zhang <zhangwm@marvell.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Neil Zhang 2011-12-15 19:26:39 +08:00 committed by Felipe Balbi
parent 86bb702813
commit 91d959d8e5

View File

@ -276,11 +276,12 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
static int queue_dtd(struct mv_ep *ep, struct mv_req *req) static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
{ {
u32 tmp, epstatus, bit_pos, direction;
struct mv_udc *udc; struct mv_udc *udc;
struct mv_dqh *dqh; struct mv_dqh *dqh;
u32 bit_pos, direction;
u32 usbcmd, epstatus;
unsigned int loops; unsigned int loops;
int readsafe, retval = 0; int retval = 0;
udc = ep->udc; udc = ep->udc;
direction = ep_dir(ep); direction = ep_dir(ep);
@ -293,30 +294,18 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
lastreq = list_entry(ep->queue.prev, struct mv_req, queue); lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
lastreq->tail->dtd_next = lastreq->tail->dtd_next =
req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
if (readl(&udc->op_regs->epprime) & bit_pos) {
loops = LOOPS(PRIME_TIMEOUT); wmb();
while (readl(&udc->op_regs->epprime) & bit_pos) {
if (loops == 0) { if (readl(&udc->op_regs->epprime) & bit_pos)
retval = -ETIME; goto done;
goto done;
}
udelay(LOOPS_USEC);
loops--;
}
if (readl(&udc->op_regs->epstatus) & bit_pos)
goto done;
}
readsafe = 0;
loops = LOOPS(READSAFE_TIMEOUT); loops = LOOPS(READSAFE_TIMEOUT);
while (readsafe == 0) { while (1) {
if (loops == 0) {
retval = -ETIME;
goto done;
}
/* start with setting the semaphores */ /* start with setting the semaphores */
tmp = readl(&udc->op_regs->usbcmd); usbcmd = readl(&udc->op_regs->usbcmd);
tmp |= USBCMD_ATDTW_TRIPWIRE_SET; usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET;
writel(tmp, &udc->op_regs->usbcmd); writel(usbcmd, &udc->op_regs->usbcmd);
/* read the endpoint status */ /* read the endpoint status */
epstatus = readl(&udc->op_regs->epstatus) & bit_pos; epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
@ -329,98 +318,46 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
* primed. * primed.
*/ */
if (readl(&udc->op_regs->usbcmd) if (readl(&udc->op_regs->usbcmd)
& USBCMD_ATDTW_TRIPWIRE_SET) { & USBCMD_ATDTW_TRIPWIRE_SET)
readsafe = 1; break;
}
loops--; loops--;
if (loops == 0) {
dev_err(&udc->dev->dev,
"Timeout for ATDTW_TRIPWIRE...\n");
retval = -ETIME;
goto done;
}
udelay(LOOPS_USEC); udelay(LOOPS_USEC);
} }
/* Clear the semaphore */ /* Clear the semaphore */
tmp = readl(&udc->op_regs->usbcmd); usbcmd = readl(&udc->op_regs->usbcmd);
tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR; usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
writel(tmp, &udc->op_regs->usbcmd); writel(usbcmd, &udc->op_regs->usbcmd);
/* If endpoint is not active, we activate it now. */ if (epstatus)
if (!epstatus) { goto done;
if (direction == EP_DIR_IN) {
struct mv_dtd *curr_dtd = dma_to_virt(
&udc->dev->dev, dqh->curr_dtd_ptr);
loops = LOOPS(DTD_TIMEOUT);
while (curr_dtd->size_ioc_sts
& DTD_STATUS_ACTIVE) {
if (loops == 0) {
retval = -ETIME;
goto done;
}
loops--;
udelay(LOOPS_USEC);
}
}
/* No other transfers on the queue */
/* Write dQH next pointer and terminate bit to 0 */
dqh->next_dtd_ptr = req->head->td_dma
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
dqh->size_ioc_int_sts = 0;
/*
* Ensure that updates to the QH will
* occur before priming.
*/
wmb();
/* Prime the Endpoint */
writel(bit_pos, &udc->op_regs->epprime);
}
} else {
/* Write dQH next pointer and terminate bit to 0 */
dqh->next_dtd_ptr = req->head->td_dma
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
dqh->size_ioc_int_sts = 0;
/* Ensure that updates to the QH will occur before priming. */
wmb();
/* Prime the Endpoint */
writel(bit_pos, &udc->op_regs->epprime);
if (direction == EP_DIR_IN) {
/* FIXME add status check after prime the IN ep */
int prime_again;
u32 curr_dtd_ptr = dqh->curr_dtd_ptr;
loops = LOOPS(DTD_TIMEOUT);
prime_again = 0;
while ((curr_dtd_ptr != req->head->td_dma)) {
curr_dtd_ptr = dqh->curr_dtd_ptr;
if (loops == 0) {
dev_err(&udc->dev->dev,
"failed to prime %s\n",
ep->name);
retval = -ETIME;
goto done;
}
loops--;
udelay(LOOPS_USEC);
if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) {
if (prime_again)
goto done;
dev_info(&udc->dev->dev,
"prime again\n");
writel(bit_pos,
&udc->op_regs->epprime);
prime_again = 1;
}
}
}
} }
/* Write dQH next pointer and terminate bit to 0 */
dqh->next_dtd_ptr = req->head->td_dma
& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
/* clear active and halt bit, in case set from a previous error */
dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
/* Ensure that updates to the QH will occure before priming. */
wmb();
/* Prime the Endpoint */
writel(bit_pos, &udc->op_regs->epprime);
done: done:
return retval; return retval;
} }
static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length, static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
dma_addr_t *dma, int *is_last) dma_addr_t *dma, int *is_last)
{ {