* [3/3] usb: dwc2: Add High Bandwidth ISOC OUT support
@ 2018-03-16 18:07 kbuild test robot
0 siblings, 0 replies; 2+ messages in thread
From: kbuild test robot @ 2018-03-16 18:07 UTC (permalink / raw)
To: Minas Harutyunyan
Cc: kbuild-all, John Youn, Felipe Balbi, Greg Kroah-Hartman, linux-usb
Hi Minas,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on next-20180309]
[cannot apply to v4.16-rc4 v4.16-rc3 v4.16-rc2 v4.16-rc5]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Minas-Harutyunyan/usb-dwc2-gadget-Update-ISOC-DDMA-flow/20180317-012732
config: i386-randconfig-x075-201810 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All warnings (new ones prefixed by >>):
drivers/usb/dwc2/gadget.c: In function 'dwc2_gadget_start_isoc_ddma':
>> drivers/usb/dwc2/gadget.c:944:3: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
^~
drivers/usb/dwc2/gadget.c:948:4: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
dwc2_writel(DXEPINT_OUTTKNEPDIS,
^~~~~~~~~~~
drivers/usb/dwc2/gadget.c: In function 'dwc2_gadget_complete_isoc_request_ddma':
drivers/usb/dwc2/gadget.c:2233:4: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (sumofpid != 0)
^~
drivers/usb/dwc2/gadget.c:2235:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
break;
^~~~~
drivers/usb/dwc2/gadget.c:2237:4: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (sumofpid != 5)
^~
drivers/usb/dwc2/gadget.c:2239:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
break;
^~~~~
drivers/usb/dwc2/gadget.c:2241:4: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
if (sumofpid != 7)
^~
drivers/usb/dwc2/gadget.c:2243:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
break;
^~~~~
vim +/if +944 drivers/usb/dwc2/gadget.c
887
888 /*
889 * dwc2_gadget_start_isoc_ddma - start isochronous transfer in DDMA
890 * @hs_ep: The isochronous endpoint.
891 *
892 * Prepare descriptor chain for isochronous endpoints. Afterwards
893 * write DMA address to HW and enable the endpoint.
894 */
895 static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
896 {
897 struct dwc2_hsotg *hsotg = hs_ep->parent;
898 struct dwc2_hsotg_req *hs_req, *treq;
899 int index = hs_ep->index;
900 int ret;
901 u32 dma_reg;
902 u32 depctl;
903 u32 ctrl;
904 struct dwc2_dma_desc *desc;
905 int dpi;
906
907 if (list_empty(&hs_ep->queue)) {
908 hs_ep->target_frame = TARGET_FRAME_INITIAL;
909 dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__);
910 return;
911 }
912
913 /* Descriptor count per interval (dpi): for IN set to 1, for OUT
914 * set to mult, i.e. 1 descritor per each packet in frame
915 */
916 dpi = 1;
917 if (!hs_ep->dir_in)
918 dpi = hs_ep->mc;
919
920 /* Initialize descriptor chain by Host Busy status */
921 for (ret = 0; ret < dpi * MAX_DMA_DESC_NUM_GENERIC; ret++) {
922 desc = &hs_ep->desc_list[ret];
923 desc->status = 0;
924 desc->status |= (DEV_DMA_BUFF_STS_HBUSY
925 << DEV_DMA_BUFF_STS_SHIFT);
926 }
927
928 hs_ep->next_desc = 0;
929 list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) {
930 ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma,
931 hs_req->req.length);
932 if (ret)
933 break;
934 }
935
936 depctl = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index);
937 dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index);
938
939 /* write descriptor chain address to control register */
940 dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg);
941
942 /* Wait for EOPF interrupt for current (u)frame */
943 if (dpi > 1) {
> 944 if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
945 GINTSTS_EOPF, 100))
946 dev_warn(hsotg->dev,
947 "%s: timeout GINTSTS.EOPF\n", __func__);
948 dwc2_writel(DXEPINT_OUTTKNEPDIS,
949 hsotg->regs + DOEPINT(hs_ep->index));
950 }
951
952 ctrl = dwc2_readl(hsotg->regs + depctl);
953 ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK;
954 dwc2_writel(ctrl, hsotg->regs + depctl);
955 }
956
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
^ permalink raw reply [flat|nested] 2+ messages in thread
* [3/3] usb: dwc2: Add High Bandwidth ISOC OUT support
@ 2018-03-16 8:09 Minas Harutyunyan
0 siblings, 0 replies; 2+ messages in thread
From: Minas Harutyunyan @ 2018-03-16 8:09 UTC (permalink / raw)
To: John Youn, Felipe Balbi, Greg Kroah-Hartman, linux-usb; +Cc: Minas Harutyunyan
Updated checking of chain full condition based on mult count.
For each packet in uframe (dpi) created new desc by
setting size of transfer to mps. Buffer addresses in descs
differ by mps in function dwc2_gadget_fill_isoc_desc().
In function dwc2_gadget_start_isoc_ddma() upadted loop
boundaries according to desc chain length.
In function dwc2_hsotg_ep_queue() added request length
checking for HB ISOC OUT transfers. Added dword aligned
limitation on maxpacket size for HB ISOC OUT's.
In function dwc2_gadget_complete_isoc_request_ddma()
separated processing of descs for HB ISOC OUT.
If completed descs PID equal MDATA do nothing, else
get remaining for frame descs and process them.
Actual length accumulated based on descs. Break
execution of the loop if data packet PID not MDATA.
If host sends less than mult data packets then skipping
unused desc for current uframe by restarting ISOC transfers.
In function dwc2_hsotg_ep_enable() desc chain allocation/
deallocation increased by mult times. Added bInterval
limit checking for HB ISOC OUT because on completion frame
number from desc used to check frame elapsed or no.
Signed-off-by: Minas Harutyunyan <hminas@synopsys.com>
---
drivers/usb/dwc2/gadget.c | 348 +++++++++++++++++++++++++++++++++++++---------
1 file changed, 284 insertions(+), 64 deletions(-)
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 1b9c84cb58fb..6f081b456e61 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -806,55 +806,82 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep,
u32 index;
u32 maxsize = 0;
u32 mask = 0;
+ int dpi, i;
+ /* Get descritor length limits */
maxsize = dwc2_gadget_get_desc_params(hs_ep, &mask);
index = hs_ep->next_desc;
- desc = &hs_ep->desc_list[index];
+
+ dpi = 1;
+ if (!hs_ep->dir_in)
+ dpi = hs_ep->mc;
/* Check if descriptor chain full */
- if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) ==
- DEV_DMA_BUFF_STS_HREADY) {
- dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__);
- return 1;
+ for (i = 0; i < dpi; i++) {
+ /* Check descriptor chain rollover */
+ if ((index + i) >= dpi * MAX_DMA_DESC_NUM_GENERIC)
+ index = -1;
+
+ desc = &hs_ep->desc_list[index + i];
+ if ((desc->status >> DEV_DMA_BUFF_STS_SHIFT) ==
+ DEV_DMA_BUFF_STS_HREADY) {
+ dev_dbg(hsotg->dev, "%s: desc chain full\n", __func__);
+ return 1;
+ }
}
- /* Clear L bit of previous desc if more than one entries in the chain */
- if (hs_ep->next_desc)
- hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L;
+ for (i = 0; i < dpi; i++) {
+ index = hs_ep->next_desc;
- dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n",
- __func__, hs_ep->index, hs_ep->dir_in ? "in" : "out", index);
+ /* Clear L bit of previous desc if more
+ * than one entries in the chain
+ */
+ if (hs_ep->next_desc)
+ hs_ep->desc_list[index - 1].status &= ~DEV_DMA_L;
- desc->status = 0;
- desc->status |= (DEV_DMA_BUFF_STS_HBUSY << DEV_DMA_BUFF_STS_SHIFT);
+ desc = &hs_ep->desc_list[index];
- desc->buf = dma_buff;
- desc->status |= (DEV_DMA_L | DEV_DMA_IOC |
- ((len << DEV_DMA_NBYTES_SHIFT) & mask));
+ dev_dbg(hsotg->dev, "%s: Filling ep %d, dir %s isoc desc # %d\n",
+ __func__, hs_ep->index, hs_ep->dir_in ? "in" : "out",
+ index);
- if (hs_ep->dir_in) {
- desc->status |= ((hs_ep->mc << DEV_DMA_ISOC_PID_SHIFT) &
- DEV_DMA_ISOC_PID_MASK) |
- ((len % hs_ep->ep.maxpacket) ?
- DEV_DMA_SHORT : 0) |
- ((hs_ep->target_frame <<
- DEV_DMA_ISOC_FRNUM_SHIFT) &
- DEV_DMA_ISOC_FRNUM_MASK);
- }
+ desc->status = 0;
+ desc->status |= (DEV_DMA_BUFF_STS_HBUSY <<
+ DEV_DMA_BUFF_STS_SHIFT);
- desc->status &= ~DEV_DMA_BUFF_STS_MASK;
- desc->status |= (DEV_DMA_BUFF_STS_HREADY << DEV_DMA_BUFF_STS_SHIFT);
+ desc->buf = dma_buff + i * hs_ep->ep.maxpacket;
+ desc->status |= (DEV_DMA_L | DEV_DMA_IOC);
+ if (hs_ep->dir_in)
+ desc->status |= ((len << DEV_DMA_NBYTES_SHIFT)
+ & mask);
+ else
+ desc->status |= ((hs_ep->ep.maxpacket <<
+ DEV_DMA_NBYTES_SHIFT) & mask);
+
+ if (hs_ep->dir_in) {
+ desc->status |= ((hs_ep->mc << DEV_DMA_ISOC_PID_SHIFT) &
+ DEV_DMA_ISOC_PID_MASK) |
+ ((len % hs_ep->ep.maxpacket) ?
+ DEV_DMA_SHORT : 0) |
+ ((hs_ep->target_frame <<
+ DEV_DMA_ISOC_FRNUM_SHIFT) &
+ DEV_DMA_ISOC_FRNUM_MASK);
+ }
- /* Increment frame number by interval for IN */
- if (hs_ep->dir_in)
- dwc2_gadget_incr_frame_num(hs_ep);
+ desc->status &= ~DEV_DMA_BUFF_STS_MASK;
+ desc->status |= (DEV_DMA_BUFF_STS_HREADY
+ << DEV_DMA_BUFF_STS_SHIFT);
- /* Update index of last configured entry in the chain */
- hs_ep->next_desc++;
- if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_GENERIC)
- hs_ep->next_desc = 0;
+ /* Increment frame number by interval for IN */
+ if (hs_ep->dir_in)
+ dwc2_gadget_incr_frame_num(hs_ep);
+ /* Update index of last configured entry in the chain */
+ hs_ep->next_desc++;
+ if (hs_ep->next_desc >= dpi * MAX_DMA_DESC_NUM_GENERIC)
+ hs_ep->next_desc = 0;
+ }
return 0;
}
@@ -875,14 +902,23 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
u32 depctl;
u32 ctrl;
struct dwc2_dma_desc *desc;
+ int dpi;
if (list_empty(&hs_ep->queue)) {
+ hs_ep->target_frame = TARGET_FRAME_INITIAL;
dev_dbg(hsotg->dev, "%s: No requests in queue\n", __func__);
return;
}
+ /* Descriptor count per interval (dpi): for IN set to 1, for OUT
+ * set to mult, i.e. 1 descritor per each packet in frame
+ */
+ dpi = 1;
+ if (!hs_ep->dir_in)
+ dpi = hs_ep->mc;
+
/* Initialize descriptor chain by Host Busy status */
- for (ret = 0; ret < MAX_DMA_DESC_NUM_GENERIC; ret++) {
+ for (ret = 0; ret < dpi * MAX_DMA_DESC_NUM_GENERIC; ret++) {
desc = &hs_ep->desc_list[ret];
desc->status = 0;
desc->status |= (DEV_DMA_BUFF_STS_HBUSY
@@ -903,6 +939,16 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
/* write descriptor chain address to control register */
dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg);
+ /* Wait for EOPF interrupt for current (u)frame */
+ if (dpi > 1) {
+ if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
+ GINTSTS_EOPF, 100))
+ dev_warn(hsotg->dev,
+ "%s: timeout GINTSTS.EOPF\n", __func__);
+ dwc2_writel(DXEPINT_OUTTKNEPDIS,
+ hsotg->regs + DOEPINT(hs_ep->index));
+ }
+
ctrl = dwc2_readl(hsotg->regs + depctl);
ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK;
dwc2_writel(ctrl, hsotg->regs + depctl);
@@ -1309,10 +1355,17 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
req->length, maxsize);
return -EINVAL;
}
- /* ISOC OUT high bandwidth not supported */
- if (!hs_ep->dir_in && req->length > hs_ep->ep.maxpacket) {
- dev_err(hs->dev, "ISOC OUT: wrong length %d (mps=%d)\n",
- req->length, hs_ep->ep.maxpacket);
+ /* Checkings for ISOC OUT including high bandwidth */
+ if (!hs_ep->dir_in &&
+ hs_ep->mc > 1 && (hs_ep->ep.maxpacket % 4)) {
+ dev_err(hs->dev, "mps not a dword aligned:%d\n",
+ hs_ep->ep.maxpacket);
+ return -EINVAL;
+ }
+ if (!hs_ep->dir_in &&
+ (req->length > (hs_ep->mc * hs_ep->ep.maxpacket))) {
+ dev_err(hs->dev, "wrong len %d > mult*mps=%d\n",
+ req->length, hs_ep->mc * hs_ep->ep.maxpacket);
return -EINVAL;
}
}
@@ -2015,6 +2068,9 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg,
dwc2_gadget_start_next_request(hs_ep);
}
+static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
+ struct dwc2_hsotg_ep *hs_ep);
+
/*
* dwc2_gadget_complete_isoc_request_ddma - complete an isoc request in DDMA
* @hs_ep: The endpoint the request was on.
@@ -2029,18 +2085,28 @@ static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep)
struct dwc2_hsotg *hsotg = hs_ep->parent;
struct dwc2_hsotg_req *hs_req;
struct usb_request *ureq;
- int index;
+ int index, idx;
dma_addr_t dma_addr;
u32 dma_reg;
u32 depdma;
u32 desc_sts;
u32 mask;
+ int dpi;
+ int ret;
+ int sumofpid;
+
+ dpi = 1;
+ if (!hs_ep->dir_in)
+ dpi = hs_ep->mc;
hs_req = get_ep_head(hs_ep);
if (!hs_req) {
+ hs_ep->target_frame = TARGET_FRAME_INITIAL;
+ dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n", __func__);
return;
}
+
ureq = &hs_req->req;
dma_addr = hs_ep->desc_list_dma;
@@ -2051,25 +2117,162 @@ static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep)
index = (depdma - dma_addr) / sizeof(struct dwc2_dma_desc) - 1;
/* Check descriptor chain rollover */
if (index < 0)
- index = MAX_DMA_DESC_NUM_GENERIC - 1;
+ index = dpi * MAX_DMA_DESC_NUM_GENERIC - 1;
desc_sts = hs_ep->desc_list[index].status;
- /* Check completion status */
- if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT ==
- DEV_DMA_STS_SUCC) {
- mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK :
- DEV_DMA_ISOC_RX_NBYTES_MASK;
- ureq->actual = ureq->length -
- ((desc_sts & mask) >>
- DEV_DMA_ISOC_NBYTES_SHIFT);
-
- /* Adjust actual len for ISOC Out if len is not align of 4 */
- if (!hs_ep->dir_in && ureq->length & 0x3)
- ureq->actual += 4 - (ureq->length & 0x3);
- dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+ if (dpi == 1) {
+ /* Check completion status for not High Bandwidth ISOC Out */
+ if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT ==
+ DEV_DMA_STS_SUCC) {
+ mask = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_MASK :
+ DEV_DMA_ISOC_RX_NBYTES_MASK;
+ ureq->actual = ureq->length -
+ ((desc_sts & mask) >>
+ DEV_DMA_ISOC_NBYTES_SHIFT);
+
+ /* Adjust actual len for ISOC Out if len is
+ * not align of 4.
+ */
+ if (!hs_ep->dir_in && dpi == 1 && ureq->length & 0x3)
+ ureq->actual += 4 - (ureq->length & 0x3);
+
+ dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+ } else {
+ dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req,
+ -ETIMEDOUT);
+ }
} else {
- dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, -ETIMEDOUT);
+ /* Check completion status for High Bandwidth ISOC Out. */
+ ret = 0;
+ /* Ignore interrupt if it not last in uframe. */
+ if (((desc_sts & DEV_DMA_ISOC_PID_MASK) >>
+ DEV_DMA_ISOC_PID_SHIFT) == DEV_DMA_ISOC_PID_MDATA)
+ return;
+
+ idx = 0;
+ /* Complete requests with NODATA if some uframes are skiped */
+ while (hs_ep->target_frame !=
+ (desc_sts & DEV_DMA_ISOC_FRNUM_MASK)
+ >> DEV_DMA_ISOC_FRNUM_SHIFT) {
+ idx++;
+ dwc2_hsotg_complete_request(hsotg, hs_ep,
+ hs_req, -ENODATA);
+ hs_req = get_ep_head(hs_ep);
+ if (!hs_req) {
+ hs_ep->target_frame = TARGET_FRAME_INITIAL;
+ dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
+ dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n",
+ __func__);
+ /* Clear late XFERCOMPL interrupts if any */
+ dwc2_writel(DXEPINT_XFERCOMPL, hsotg->regs +
+ DOEPINT(hs_ep->index));
+ return;
+ }
+
+ ureq = &hs_req->req;
+
+ dwc2_gadget_incr_frame_num(hs_ep);
+ hs_ep->target_frame &= (DEV_DMA_ISOC_FRNUM_MASK >>
+ DEV_DMA_ISOC_FRNUM_SHIFT);
+ }
+ /* Increment 1 more to set target to next uframe */
+ hs_ep->target_frame = (desc_sts & DEV_DMA_ISOC_FRNUM_MASK) >>
+ DEV_DMA_ISOC_FRNUM_SHIFT;
+ dwc2_gadget_incr_frame_num(hs_ep);
+ hs_ep->target_frame &= (DEV_DMA_ISOC_FRNUM_MASK >>
+ DEV_DMA_ISOC_FRNUM_SHIFT);
+
+ /* Need to restart if any request completed in above loop */
+ if (idx) {
+ dwc2_hsotg_complete_request(hsotg, hs_ep,
+ hs_req, -ENODATA);
+ hs_req = get_ep_head(hs_ep);
+ if (!hs_req) {
+ hs_ep->target_frame = TARGET_FRAME_INITIAL;
+ dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
+ dev_warn(hsotg->dev, "%s: ISOC EP queue empty\n",
+ __func__);
+ /* Clear any late XFERCOMPL interrupts if any */
+ dwc2_writel(DXEPINT_XFERCOMPL, hsotg->regs +
+ DOEPINT(hs_ep->index));
+ return;
+ }
+ goto out;
+ }
+ ureq = &hs_req->req;
+
+ /* Because of interrupt latency after receiving interrupt
+ * for 1st descriptor and when start handling the descriptor
+ * index can be shifted to second or third descriptor.
+ * On last descriptor (for uframe) completion process all
+ * descritors for current uframe.
+ */
+ sumofpid = 0;
+
+ for (idx = (index / dpi) * dpi; idx <= index; idx++) {
+ desc_sts = hs_ep->desc_list[idx].status;
+
+ if ((desc_sts & DEV_DMA_STS_MASK) >> DEV_DMA_STS_SHIFT
+ == DEV_DMA_STS_SUCC) {
+ ureq->actual += hs_ep->ep.maxpacket -
+ ((desc_sts &
+ DEV_DMA_ISOC_RX_NBYTES_MASK) >>
+ DEV_DMA_ISOC_NBYTES_SHIFT);
+ sumofpid += (desc_sts & DEV_DMA_ISOC_PID_MASK)
+ >> DEV_DMA_ISOC_PID_SHIFT;
+ } else {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ /* Safety check packets PID sequence based on sumofpids:
+ * if packet count = 1 then sumofpid should be 0
+ * if packet count = 2 then sumofpid should be 3+2=5
+ * if packet count = 3 then sumofpid should be 3+3+1=7
+ */
+ switch (index - (index / dpi) * dpi + 1) {
+ case 1:
+ if (sumofpid != 0)
+ ret = -ETIMEDOUT;
+ break;
+ case 2:
+ if (sumofpid != 5)
+ ret = -ETIMEDOUT;
+ break;
+ case 3:
+ if (sumofpid != 7)
+ ret = -ETIMEDOUT;
+ break;
+ default:
+ dev_dbg(hsotg->dev, "%s: wrong sum of PID's %d\n",
+ __func__, sumofpid);
+ }
+
+ /* Clear EOPF intr for frame if some descs should be skiped */
+ if ((index - (index / dpi) * dpi + 1) < dpi)
+ dwc2_writel(GINTSTS_EOPF, hsotg->regs + GINTSTS);
+
+ /* Safety check */
+ if (ureq->actual > ureq->length)
+ ureq->actual = ureq->length;
+
+ dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, ret);
+
+ /* If packet count in current uframe less than mult then need
+ * to skip unused for uframe descrioptors by restarting xfers
+ */
+ idx = dpi - (index % dpi) - 1;
+out:
+ if (idx > 0) {
+ dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
+ dwc2_gadget_start_isoc_ddma(hs_ep);
+ }
+
+ /* Clear late XFERCOMPL and OUTTKNEPDIS interrupts if any */
+ dwc2_writel(DXEPINT_XFERCOMPL || DXEPINT_OUTTKNEPDIS,
+ hsotg->regs + DOEPINT(hs_ep->index));
}
}
@@ -2744,12 +2947,17 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep)
*/
tmp = dwc2_hsotg_read_frameno(hsotg);
- dwc2_hsotg_complete_request(hsotg, ep, get_ep_head(ep), -ENODATA);
-
if (using_desc_dma(hsotg)) {
if (ep->target_frame == TARGET_FRAME_INITIAL) {
+ dwc2_hsotg_complete_request(hsotg, ep,
+ get_ep_head(ep), -ENODATA);
/* Start first ISO Out */
ep->target_frame = tmp;
+ dwc2_gadget_incr_frame_num(ep);
+ ep->target_frame &= (DEV_DMA_ISOC_FRNUM_MASK >>
+ DEV_DMA_ISOC_FRNUM_SHIFT);
+ /* Clear EOPF interrupt */
+ dwc2_writel(GINTSTS_EOPF, hsotg->regs + GINTSTS);
dwc2_gadget_start_isoc_ddma(ep);
}
return;
@@ -3774,6 +3982,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
unsigned int i, val, size;
int ret = 0;
unsigned char ep_type;
+ int dpi;
dev_dbg(hsotg->dev,
"%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n",
@@ -3792,17 +4001,20 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
return -EINVAL;
}
+ mc = usb_endpoint_maxp_mult(desc);
+
ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
/* ISOC DDMA supported bInterval up to 12 */
- if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC &&
- dir_in && desc->bInterval > 12) {
- dev_err(hsotg->dev,
- "%s: ISOC IN: bInterval>12 not supported!\n", __func__);
- return -EINVAL;
+ if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC) {
+ if ((dir_in || (!dir_in && mc > 1)) && desc->bInterval > 12) {
+ dev_err(hsotg->dev,
+ "%s: ISOC IN/OUT(HB): bInterval>12 not supported!\n",
+ __func__);
+ return -EINVAL;
+ }
}
mps = usb_endpoint_maxp(desc);
- mc = usb_endpoint_maxp_mult(desc);
/* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */
@@ -3812,10 +4024,18 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
__func__, epctrl, epctrl_reg);
+ /* ISOC Descriptor count per interval (dpi): for IN set to 1,
+ * for OUT set to mult, i.e. 1 descritor per each packet in frame
+ */
+ dpi = 1;
+ if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC &&
+ !dir_in)
+ dpi = mc;
+
/* Allocate DMA descriptor chain for non-ctrl endpoints */
if (using_desc_dma(hsotg) && !hs_ep->desc_list) {
hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev,
- MAX_DMA_DESC_NUM_GENERIC *
+ dpi * MAX_DMA_DESC_NUM_GENERIC *
sizeof(struct dwc2_dma_desc),
&hs_ep->desc_list_dma, GFP_ATOMIC);
if (!hs_ep->desc_list) {
@@ -3936,7 +4156,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
error2:
if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) {
- dmam_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC *
+ dmam_free_coherent(hsotg->dev, dpi * MAX_DMA_DESC_NUM_GENERIC *
sizeof(struct dwc2_dma_desc),
hs_ep->desc_list, hs_ep->desc_list_dma);
hs_ep->desc_list = NULL;
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2018-03-16 18:07 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-16 18:07 [3/3] usb: dwc2: Add High Bandwidth ISOC OUT support kbuild test robot
-- strict thread matches above, loose matches on Subject: below --
2018-03-16 8:09 Minas Harutyunyan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.