|
|
@@ -522,6 +522,20 @@ static void free_pending_td(struct ci_hw_ep *hwep)
|
|
|
kfree(pending);
|
|
|
}
|
|
|
|
|
|
+static int reprime_dtd(struct ci_hdrc *ci, struct ci_hw_ep *hwep,
|
|
|
+ struct td_node *node)
|
|
|
+{
|
|
|
+ hwep->qh.ptr->td.next = node->dma;
|
|
|
+ hwep->qh.ptr->td.token &=
|
|
|
+ cpu_to_le32(~(TD_STATUS_HALTED | TD_STATUS_ACTIVE));
|
|
|
+
|
|
|
+ /* Synchronize before ep prime */
|
|
|
+ wmb();
|
|
|
+
|
|
|
+ return hw_ep_prime(ci, hwep->num, hwep->dir,
|
|
|
+ hwep->type == USB_ENDPOINT_XFER_CONTROL);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* _hardware_dequeue: handles a request at hardware level
|
|
|
* @gadget: gadget
|
|
|
@@ -535,6 +549,7 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
|
|
|
struct td_node *node, *tmpnode;
|
|
|
unsigned remaining_length;
|
|
|
unsigned actual = hwreq->req.length;
|
|
|
+ struct ci_hdrc *ci = hwep->ci;
|
|
|
|
|
|
if (hwreq->req.status != -EALREADY)
|
|
|
return -EINVAL;
|
|
|
@@ -544,6 +559,11 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
|
|
|
list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) {
|
|
|
tmptoken = le32_to_cpu(node->ptr->token);
|
|
|
if ((TD_STATUS_ACTIVE & tmptoken) != 0) {
|
|
|
+ int n = hw_ep_bit(hwep->num, hwep->dir);
|
|
|
+
|
|
|
+ if (ci->rev == CI_REVISION_24)
|
|
|
+ if (!hw_read(ci, OP_ENDPTSTAT, BIT(n)))
|
|
|
+ reprime_dtd(ci, hwep, node);
|
|
|
hwreq->req.status = -EALREADY;
|
|
|
return -EBUSY;
|
|
|
}
|