diff options
author | Anton Tikhomirov <av.tikhomirov@samsung.com> | 2011-04-21 04:06:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-05-02 20:00:26 -0400 |
commit | 9c39ddc60ee9eb70569d1658e512cfa232b9dd16 (patch) | |
tree | 01ef19e58780ec7403f465cd5b3a3e5a7e7c5cb6 | |
parent | 26ab3d0ce95c270b1ca491d6970aa14852d8e5a3 (diff) |
USB: s3c-hsotg: Fix stall condition processing
The following should be done for requests after endpoint stall
condition is cleared:
1) 'in progress' request (if any) should be completed since
Tx FIFO was flushed;
2) next request from queue (if any) should be started.
This commit does that.
Additionally set/clear stall condition code is fixed.
Signed-off-by: Anton Tikhomirov <av.tikhomirov@samsung.com>
Reviewed-by: Kyoungil Kim<ki0351.kim@samsung.com>
Cc: Ben Dooks <ben-linux@fluff.org>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/gadget/s3c-hsotg.c | 142 |
1 files changed, 111 insertions, 31 deletions
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index cbbc33677fd4..6be424e2cc60 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c | |||
@@ -679,6 +679,14 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, | |||
679 | __func__, readl(hsotg->regs + epctrl_reg), index, | 679 | __func__, readl(hsotg->regs + epctrl_reg), index, |
680 | hs_ep->dir_in ? "in" : "out"); | 680 | hs_ep->dir_in ? "in" : "out"); |
681 | 681 | ||
682 | /* If endpoint is stalled, we will restart request later */ | ||
683 | ctrl = readl(hsotg->regs + epctrl_reg); | ||
684 | |||
685 | if (ctrl & S3C_DxEPCTL_Stall) { | ||
686 | dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); | ||
687 | return; | ||
688 | } | ||
689 | |||
682 | length = ureq->length - ureq->actual; | 690 | length = ureq->length - ureq->actual; |
683 | 691 | ||
684 | if (0) | 692 | if (0) |
@@ -731,18 +739,6 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, | |||
731 | /* write size / packets */ | 739 | /* write size / packets */ |
732 | writel(epsize, hsotg->regs + epsize_reg); | 740 | writel(epsize, hsotg->regs + epsize_reg); |
733 | 741 | ||
734 | ctrl = readl(hsotg->regs + epctrl_reg); | ||
735 | |||
736 | if (ctrl & S3C_DxEPCTL_Stall) { | ||
737 | dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); | ||
738 | |||
739 | /* not sure what we can do here, if it is EP0 then we should | ||
740 | * get this cleared once the endpoint has transmitted the | ||
741 | * STALL packet, otherwise it needs to be cleared by the | ||
742 | * host. | ||
743 | */ | ||
744 | } | ||
745 | |||
746 | if (using_dma(hsotg)) { | 742 | if (using_dma(hsotg)) { |
747 | unsigned int dma_reg; | 743 | unsigned int dma_reg; |
748 | 744 | ||
@@ -1048,6 +1044,20 @@ static int s3c_hsotg_process_req_status(struct s3c_hsotg *hsotg, | |||
1048 | static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value); | 1044 | static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value); |
1049 | 1045 | ||
1050 | /** | 1046 | /** |
1047 | * get_ep_head - return the first request on the endpoint | ||
1048 | * @hs_ep: The controller endpoint to get | ||
1049 | * | ||
1050 | * Get the first request on the endpoint. | ||
1051 | */ | ||
1052 | static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep) | ||
1053 | { | ||
1054 | if (list_empty(&hs_ep->queue)) | ||
1055 | return NULL; | ||
1056 | |||
1057 | return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue); | ||
1058 | } | ||
1059 | |||
1060 | /** | ||
1051 | * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE | 1061 | * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE |
1052 | * @hsotg: The device state | 1062 | * @hsotg: The device state |
1053 | * @ctrl: USB control request | 1063 | * @ctrl: USB control request |
@@ -1056,6 +1066,8 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, | |||
1056 | struct usb_ctrlrequest *ctrl) | 1066 | struct usb_ctrlrequest *ctrl) |
1057 | { | 1067 | { |
1058 | struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; | 1068 | struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; |
1069 | struct s3c_hsotg_req *hs_req; | ||
1070 | bool restart; | ||
1059 | bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); | 1071 | bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE); |
1060 | struct s3c_hsotg_ep *ep; | 1072 | struct s3c_hsotg_ep *ep; |
1061 | int ret; | 1073 | int ret; |
@@ -1081,6 +1093,29 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg, | |||
1081 | "%s: failed to send reply\n", __func__); | 1093 | "%s: failed to send reply\n", __func__); |
1082 | return ret; | 1094 | return ret; |
1083 | } | 1095 | } |
1096 | |||
1097 | if (!set) { | ||
1098 | /* | ||
1099 | * If we have request in progress, | ||
1100 | * then complete it | ||
1101 | */ | ||
1102 | if (ep->req) { | ||
1103 | hs_req = ep->req; | ||
1104 | ep->req = NULL; | ||
1105 | list_del_init(&hs_req->queue); | ||
1106 | hs_req->req.complete(&ep->ep, | ||
1107 | &hs_req->req); | ||
1108 | } | ||
1109 | |||
1110 | /* If we have pending request, then start it */ | ||
1111 | restart = !list_empty(&ep->queue); | ||
1112 | if (restart) { | ||
1113 | hs_req = get_ep_head(ep); | ||
1114 | s3c_hsotg_start_req(hsotg, ep, | ||
1115 | hs_req, false); | ||
1116 | } | ||
1117 | } | ||
1118 | |||
1084 | break; | 1119 | break; |
1085 | 1120 | ||
1086 | default: | 1121 | default: |
@@ -1248,20 +1283,6 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) | |||
1248 | } | 1283 | } |
1249 | 1284 | ||
1250 | /** | 1285 | /** |
1251 | * get_ep_head - return the first request on the endpoint | ||
1252 | * @hs_ep: The controller endpoint to get | ||
1253 | * | ||
1254 | * Get the first request on the endpoint. | ||
1255 | */ | ||
1256 | static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep) | ||
1257 | { | ||
1258 | if (list_empty(&hs_ep->queue)) | ||
1259 | return NULL; | ||
1260 | |||
1261 | return list_first_entry(&hs_ep->queue, struct s3c_hsotg_req, queue); | ||
1262 | } | ||
1263 | |||
1264 | /** | ||
1265 | * s3c_hsotg_complete_request - complete a request given to us | 1286 | * s3c_hsotg_complete_request - complete a request given to us |
1266 | * @hsotg: The device state. | 1287 | * @hsotg: The device state. |
1267 | * @hs_ep: The endpoint the request was on. | 1288 | * @hs_ep: The endpoint the request was on. |
@@ -1684,6 +1705,37 @@ bad_mps: | |||
1684 | dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); | 1705 | dev_err(hsotg->dev, "ep%d: bad mps of %d\n", ep, mps); |
1685 | } | 1706 | } |
1686 | 1707 | ||
1708 | /** | ||
1709 | * s3c_hsotg_txfifo_flush - flush Tx FIFO | ||
1710 | * @hsotg: The driver state | ||
1711 | * @idx: The index for the endpoint (0..15) | ||
1712 | */ | ||
1713 | static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) | ||
1714 | { | ||
1715 | int timeout; | ||
1716 | int val; | ||
1717 | |||
1718 | writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh, | ||
1719 | hsotg->regs + S3C_GRSTCTL); | ||
1720 | |||
1721 | /* wait until the fifo is flushed */ | ||
1722 | timeout = 100; | ||
1723 | |||
1724 | while (1) { | ||
1725 | val = readl(hsotg->regs + S3C_GRSTCTL); | ||
1726 | |||
1727 | if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0) | ||
1728 | break; | ||
1729 | |||
1730 | if (--timeout == 0) { | ||
1731 | dev_err(hsotg->dev, | ||
1732 | "%s: timeout flushing fifo (GRSTCTL=%08x)\n", | ||
1733 | __func__, val); | ||
1734 | } | ||
1735 | |||
1736 | udelay(1); | ||
1737 | } | ||
1738 | } | ||
1687 | 1739 | ||
1688 | /** | 1740 | /** |
1689 | * s3c_hsotg_trytx - check to see if anything needs transmitting | 1741 | * s3c_hsotg_trytx - check to see if anything needs transmitting |
@@ -1806,9 +1858,24 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, | |||
1806 | } | 1858 | } |
1807 | } | 1859 | } |
1808 | 1860 | ||
1809 | if (ints & S3C_DxEPINT_EPDisbld) | 1861 | if (ints & S3C_DxEPINT_EPDisbld) { |
1810 | dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); | 1862 | dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); |
1811 | 1863 | ||
1864 | if (dir_in) { | ||
1865 | int epctl = readl(hsotg->regs + epctl_reg); | ||
1866 | |||
1867 | s3c_hsotg_txfifo_flush(hsotg, idx); | ||
1868 | |||
1869 | if ((epctl & S3C_DxEPCTL_Stall) && | ||
1870 | (epctl & S3C_DxEPCTL_EPType_Bulk)) { | ||
1871 | int dctl = readl(hsotg->regs + S3C_DCTL); | ||
1872 | |||
1873 | dctl |= S3C_DCTL_CGNPInNAK; | ||
1874 | writel(dctl, hsotg->regs + S3C_DCTL); | ||
1875 | } | ||
1876 | } | ||
1877 | } | ||
1878 | |||
1812 | if (ints & S3C_DxEPINT_AHBErr) | 1879 | if (ints & S3C_DxEPINT_AHBErr) |
1813 | dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); | 1880 | dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); |
1814 | 1881 | ||
@@ -2406,6 +2473,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) | |||
2406 | unsigned long irqflags; | 2473 | unsigned long irqflags; |
2407 | u32 epreg; | 2474 | u32 epreg; |
2408 | u32 epctl; | 2475 | u32 epctl; |
2476 | u32 xfertype; | ||
2409 | 2477 | ||
2410 | dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); | 2478 | dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); |
2411 | 2479 | ||
@@ -2416,10 +2484,17 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) | |||
2416 | epreg = S3C_DIEPCTL(index); | 2484 | epreg = S3C_DIEPCTL(index); |
2417 | epctl = readl(hs->regs + epreg); | 2485 | epctl = readl(hs->regs + epreg); |
2418 | 2486 | ||
2419 | if (value) | 2487 | if (value) { |
2420 | epctl |= S3C_DxEPCTL_Stall; | 2488 | epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK; |
2421 | else | 2489 | if (epctl & S3C_DxEPCTL_EPEna) |
2490 | epctl |= S3C_DxEPCTL_EPDis; | ||
2491 | } else { | ||
2422 | epctl &= ~S3C_DxEPCTL_Stall; | 2492 | epctl &= ~S3C_DxEPCTL_Stall; |
2493 | xfertype = epctl & S3C_DxEPCTL_EPType_MASK; | ||
2494 | if (xfertype == S3C_DxEPCTL_EPType_Bulk || | ||
2495 | xfertype == S3C_DxEPCTL_EPType_Intterupt) | ||
2496 | epctl |= S3C_DxEPCTL_SetD0PID; | ||
2497 | } | ||
2423 | 2498 | ||
2424 | writel(epctl, hs->regs + epreg); | 2499 | writel(epctl, hs->regs + epreg); |
2425 | 2500 | ||
@@ -2428,8 +2503,13 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) | |||
2428 | 2503 | ||
2429 | if (value) | 2504 | if (value) |
2430 | epctl |= S3C_DxEPCTL_Stall; | 2505 | epctl |= S3C_DxEPCTL_Stall; |
2431 | else | 2506 | else { |
2432 | epctl &= ~S3C_DxEPCTL_Stall; | 2507 | epctl &= ~S3C_DxEPCTL_Stall; |
2508 | xfertype = epctl & S3C_DxEPCTL_EPType_MASK; | ||
2509 | if (xfertype == S3C_DxEPCTL_EPType_Bulk || | ||
2510 | xfertype == S3C_DxEPCTL_EPType_Intterupt) | ||
2511 | epctl |= S3C_DxEPCTL_SetD0PID; | ||
2512 | } | ||
2433 | 2513 | ||
2434 | writel(epctl, hs->regs + epreg); | 2514 | writel(epctl, hs->regs + epreg); |
2435 | 2515 | ||