From bc5081617faeb3b2f0c126dc37264b87af7da47f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 4 Feb 2016 14:18:01 +0200 Subject: [PATCH 01/57] usb: dwc3: drop FIFO resizing logic That FIFO resizing logic was added to support OMAP5 ES1.0 which had a bogus default FIFO size. I can't remember the exact size of default FIFO, but it was less than one bulk superspeed packet (<1024) which would prevent USB3 from ever working on OMAP5 ES1.0. However, OMAP5 ES1.0 support has been dropped by commit aa2f4b16f830 ("ARM: OMAP5: id: Remove ES1.0 support") which renders FIFO resizing unnecessary. Tested-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- .../devicetree/bindings/usb/dwc3.txt | 4 +- .../devicetree/bindings/usb/qcom,dwc3.txt | 1 - drivers/usb/dwc3/core.c | 4 - drivers/usb/dwc3/core.h | 5 -- drivers/usb/dwc3/ep0.c | 9 -- drivers/usb/dwc3/gadget.c | 86 ------------------- drivers/usb/dwc3/platform_data.h | 1 - 7 files changed, 2 insertions(+), 108 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index fb2ad0acedbd..15695682a480 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -14,7 +14,6 @@ Optional properties: the second element is expected to be a handle to the USB3/SS PHY - phys: from the *Generic PHY* bindings - phy-names: from the *Generic PHY* bindings - - tx-fifo-resize: determines if the FIFO *has* to be reallocated. - snps,usb3_lpm_capable: determines if platform is USB3 LPM capable - snps,disable_scramble_quirk: true when SW should disable data scrambling. Only really useful for FPGA builds. @@ -47,6 +46,8 @@ Optional properties: register for post-silicon frame length adjustment when the fladj_30mhz_sdbnd signal is invalid or incorrect. + - tx-fifo-resize: determines if the FIFO *has* to be reallocated. + This is usually a subnode to DWC3 glue to which it is connected. dwc3@4a030000 { @@ -54,5 +55,4 @@ dwc3@4a030000 { reg = <0x4a030000 0xcfff>; interrupts = <0 92 4> usb-phy = <&usb2_phy>, <&usb3,phy>; - tx-fifo-resize; }; diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt index ca164e71dd50..39acb084bce9 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt @@ -59,7 +59,6 @@ Example device nodes: interrupts = <0 205 0x4>; phys = <&hs_phy>, <&ss_phy>; phy-names = "usb2-phy", "usb3-phy"; - tx-fifo-resize; dr_mode = "host"; }; }; diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index fa20f5a99d12..67d183a18baa 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -882,9 +882,6 @@ static int dwc3_probe(struct platform_device *pdev) dwc->usb3_lpm_capable = device_property_read_bool(dev, "snps,usb3_lpm_capable"); - dwc->needs_fifo_resize = device_property_read_bool(dev, - "tx-fifo-resize"); - dwc->disable_scramble_quirk = device_property_read_bool(dev, "snps,disable_scramble_quirk"); dwc->u2exit_lfps_quirk = device_property_read_bool(dev, @@ -926,7 +923,6 @@ static int dwc3_probe(struct platform_device *pdev) if (pdata->hird_threshold) hird_threshold = pdata->hird_threshold; - dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->usb3_lpm_capable = pdata->usb3_lpm_capable; dwc->dr_mode = pdata->dr_mode; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 6254b2ff9080..7cbe9e93a6b2 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -709,9 +709,7 @@ struct dwc3_scratchpad_array { * 0 - utmi_sleep_n * 1 - utmi_l1_suspend_n * @is_fpga: true when we are using the FPGA board - * @needs_fifo_resize: not all users might want fifo resizing, flag it * @pullups_connected: true when Run/Stop bit is set - * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @start_config_issued: true when StartConfig command has been issued * @three_stage_setup: set if we perform a three phase setup @@ -855,9 +853,7 @@ struct dwc3 { unsigned has_lpm_erratum:1; unsigned is_utmi_l1_suspend:1; unsigned is_fpga:1; - unsigned needs_fifo_resize:1; unsigned pullups_connected:1; - unsigned resize_fifos:1; unsigned setup_packet_pending:1; unsigned three_stage_setup:1; unsigned usb3_lpm_capable:1; @@ -1025,7 +1021,6 @@ struct dwc3_gadget_ep_cmd_params { /* prototypes */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode); -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc); /* check whether we are on the DWC_usb31 core */ static inline bool dwc3_is_usb31(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index eca2e6d8e041..4454de0d810c 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -586,9 +586,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= (DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); - - dwc->resize_fifos = true; - dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET"); } break; @@ -1027,12 +1024,6 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) { - if (dwc->resize_fifos) { - dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs"); - dwc3_gadget_resize_tx_fifos(dwc); - dwc->resize_fifos = 0; - } - WARN_ON(dwc3_ep0_start_control_status(dep)); } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index d54a028cdfeb..3a5c2715a3b5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -145,92 +145,6 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) return -ETIMEDOUT; } -/** - * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case - * @dwc: pointer to our context structure - * - * This function will a best effort FIFO allocation in order - * to improve FIFO usage and throughput, while still allowing - * us to enable as many endpoints as possible. - * - * Keep in mind that this operation will be highly dependent - * on the configured size for RAM1 - which contains TxFifo -, - * the amount of endpoints enabled on coreConsultant tool, and - * the width of the Master Bus. - * - * In the ideal world, we would always be able to satisfy the - * following equation: - * - * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \ - * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes - * - * Unfortunately, due to many variables that's not always the case. - */ -int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) -{ - int last_fifo_depth = 0; - int ram1_depth; - int fifo_size; - int mdwidth; - int num; - - if (!dwc->needs_fifo_resize) - return 0; - - ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7); - mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); - - /* MDWIDTH is represented in bits, we need it in bytes */ - mdwidth >>= 3; - - /* - * FIXME For now we will only allocate 1 wMaxPacketSize space - * for each enabled endpoint, later patches will come to - * improve this algorithm so that we better use the internal - * FIFO space - */ - for (num = 0; num < dwc->num_in_eps; num++) { - /* bit0 indicates direction; 1 means IN ep */ - struct dwc3_ep *dep = dwc->eps[(num << 1) | 1]; - int mult = 1; - int tmp; - - if (!(dep->flags & DWC3_EP_ENABLED)) - continue; - - if (usb_endpoint_xfer_bulk(dep->endpoint.desc) - || usb_endpoint_xfer_isoc(dep->endpoint.desc)) - mult = 3; - - /* - * REVISIT: the following assumes we will always have enough - * space available on the FIFO RAM for all possible use cases. - * Make sure that's true somehow and change FIFO allocation - * accordingly. - * - * If we have Bulk or Isochronous endpoints, we want - * them to be able to be very, very fast. So we're giving - * those endpoints a fifo_size which is enough for 3 full - * packets - */ - tmp = mult * (dep->endpoint.maxpacket + mdwidth); - tmp += mdwidth; - - fifo_size = DIV_ROUND_UP(tmp, mdwidth); - - fifo_size |= (last_fifo_depth << 16); - - dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d", - dep->name, last_fifo_depth, fifo_size & 0xffff); - - dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size); - - last_fifo_depth += (fifo_size & 0xffff); - } - - return 0; -} - void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status) { diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index 2bb4d3ad0e6b..aaa6f00df755 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -23,7 +23,6 @@ struct dwc3_platform_data { enum usb_device_speed maximum_speed; enum usb_dr_mode dr_mode; - bool tx_fifo_resize; bool usb3_lpm_capable; unsigned is_utmi_l1_suspend:1; From ca4d44ea2a91b922e1514f5ed77f6bcf3657fd67 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 10 Mar 2016 13:53:27 +0200 Subject: [PATCH 02/57] usb: dwc3: gadget: always enable CSP CSP bit of TRB Control is useful for protocols such CDC EEM/ECM/NCM where we're transferring in blocks of MTU-sized requests (usually MTU is 1500 bytes). We know we will always have a short packet after two (for HS) wMaxPacketSize packets and, usually, we will have a long(-ish) queue of requests (for our g_ether gadget, we have at least 10 requests). Instead of always stopping the queue processing to interrupt, giveback and restart, let's tell dwc3 to interrupt but continue processing following request if we have anything already pending in the queue. This gave me a considerable improvement of 40% on my test setup. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3a5c2715a3b5..28d512a65ada 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -726,6 +726,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; else trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS; + + /* always enable Interrupt on Missed ISOC */ + trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; break; case USB_ENDPOINT_XFER_BULK: @@ -740,15 +743,14 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, BUG(); } - if (!req->request.no_interrupt && !chain) - trb->ctrl |= DWC3_TRB_CTRL_IOC; + /* always enable Continue on Short Packet */ + trb->ctrl |= DWC3_TRB_CTRL_CSP; - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; - trb->ctrl |= DWC3_TRB_CTRL_CSP; - } else if (last) { + if (!req->request.no_interrupt) + trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; + + if (last) trb->ctrl |= DWC3_TRB_CTRL_LST; - } if (chain) trb->ctrl |= DWC3_TRB_CTRL_CHN; From 8495036e986bdc7e82523d47097e7833d2782ff9 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 10 Mar 2016 14:40:31 +0200 Subject: [PATCH 03/57] usb: dwc3: increase maximum number of TRBs per endpoint previously we were using a maximum of 32 TRBs per endpoint. With each TRB being 16 bytes long, we were using 512 bytes of memory for each endpoint. However, SLAB/SLUB will always allocate PAGE_SIZE chunks. In order to better utilize the memory we allocate and to allow deeper queues for gadgets which would benefit from it (g_ether comes to mind), let's increase the maximum to 256 TRBs which rounds up to 4096 bytes for each endpoint. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 7cbe9e93a6b2..5e17c02d3e92 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -438,7 +438,7 @@ struct dwc3_event_buffer { #define DWC3_EP_DIRECTION_TX true #define DWC3_EP_DIRECTION_RX false -#define DWC3_TRB_NUM 32 +#define DWC3_TRB_NUM 256 #define DWC3_TRB_MASK (DWC3_TRB_NUM - 1) /** From aa3342c8bb618ae25beccddacc3efb415c3a987b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 14 Mar 2016 11:01:31 +0200 Subject: [PATCH 04/57] usb: dwc3: better name for our request management lists request_list and req_queued were, well, weird naming choices. Let's give those better names and call them, respectively, pending_list and started_list. These new names better reflect what these lists are supposed to do. While at that also rename req->queued to req->started. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 10 +++---- drivers/usb/dwc3/ep0.c | 14 +++++----- drivers/usb/dwc3/gadget.c | 58 +++++++++++++++++++-------------------- drivers/usb/dwc3/gadget.h | 6 ++-- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 5e17c02d3e92..4ea4b51688c1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -444,8 +444,8 @@ struct dwc3_event_buffer { /** * struct dwc3_ep - device side endpoint representation * @endpoint: usb endpoint - * @request_list: list of requests for this endpoint - * @req_queued: list of requests on this ep which have TRBs setup + * @pending_list: list of pending requests for this endpoint + * @started_list: list of started requests on this endpoint * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool * @free_slot: next slot which is going to be used @@ -464,8 +464,8 @@ struct dwc3_event_buffer { */ struct dwc3_ep { struct usb_ep endpoint; - struct list_head request_list; - struct list_head req_queued; + struct list_head pending_list; + struct list_head started_list; struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; @@ -635,7 +635,7 @@ struct dwc3_request { unsigned direction:1; unsigned mapped:1; - unsigned queued:1; + unsigned started:1; }; /* diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 4454de0d810c..5e0a21b65053 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -124,7 +124,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, req->request.status = -EINPROGRESS; req->epnum = dep->number; - list_add_tail(&req->list, &dep->request_list); + list_add_tail(&req->list, &dep->pending_list); /* * Gadget driver might not be quick enough to queue a request @@ -240,7 +240,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, } /* we share one TRB for ep0/1 */ - if (!list_empty(&dep->request_list)) { + if (!list_empty(&dep->pending_list)) { ret = -EBUSY; goto out; } @@ -272,10 +272,10 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) dep->flags = DWC3_EP_ENABLED; dwc->delayed_status = false; - if (!list_empty(&dep->request_list)) { + if (!list_empty(&dep->pending_list)) { struct dwc3_request *req; - req = next_request(&dep->request_list); + req = next_request(&dep->pending_list); dwc3_gadget_giveback(dep, req, -ECONNRESET); } @@ -806,7 +806,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, trace_dwc3_complete_trb(ep0, trb); - r = next_request(&ep0->request_list); + r = next_request(&ep0->pending_list); if (!r) return; @@ -894,8 +894,8 @@ static void dwc3_ep0_complete_status(struct dwc3 *dwc, trace_dwc3_complete_trb(dep, trb); - if (!list_empty(&dep->request_list)) { - r = next_request(&dep->request_list); + if (!list_empty(&dep->pending_list)) { + r = next_request(&dep->pending_list); dwc3_gadget_giveback(dep, r, 0); } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 28d512a65ada..e6bd3a976ad9 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -151,7 +151,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, struct dwc3 *dwc = dep->dwc; int i; - if (req->queued) { + if (req->started) { i = 0; do { dep->busy_slot++; @@ -165,7 +165,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, usb_endpoint_xfer_isoc(dep->endpoint.desc)) dep->busy_slot++; } while(++i < req->request.num_mapped_sgs); - req->queued = false; + req->started = false; } list_del(&req->list); req->trb = NULL; @@ -522,19 +522,19 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; - if (!list_empty(&dep->req_queued)) { + if (!list_empty(&dep->started_list)) { dwc3_stop_active_transfer(dwc, dep->number, true); /* - giveback all requests to gadget driver */ - while (!list_empty(&dep->req_queued)) { - req = next_request(&dep->req_queued); + while (!list_empty(&dep->started_list)) { + req = next_request(&dep->started_list); dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } } - while (!list_empty(&dep->request_list)) { - req = next_request(&dep->request_list); + while (!list_empty(&dep->pending_list)) { + req = next_request(&dep->pending_list); dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } @@ -700,7 +700,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; if (!req->trb) { - dwc3_gadget_move_request_queued(req); + dwc3_gadget_move_started_request(req); req->trb = trb; req->trb_dma = dwc3_trb_dma_offset(dep, trb); req->start_slot = dep->free_slot & DWC3_TRB_MASK; @@ -824,7 +824,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) return; - list_for_each_entry_safe(req, n, &dep->request_list, list) { + list_for_each_entry_safe(req, n, &dep->pending_list, list) { unsigned length; dma_addr_t dma; last_one = false; @@ -843,7 +843,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) if (i == (request->num_mapped_sgs - 1) || sg_is_last(s)) { - if (list_empty(&dep->request_list)) + if (list_empty(&dep->pending_list)) last_one = true; chain = false; } @@ -873,7 +873,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) last_one = 1; /* Is this the last request? */ - if (list_is_last(&req->list, &dep->request_list)) + if (list_is_last(&req->list, &dep->pending_list)) last_one = 1; dwc3_prepare_one_trb(dep, req, dma, length, @@ -904,18 +904,18 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, * new requests as we try to set the IOC bit only on the last request. */ if (start_new) { - if (list_empty(&dep->req_queued)) + if (list_empty(&dep->started_list)) dwc3_prepare_trbs(dep, start_new); /* req points to the first request which will be sent */ - req = next_request(&dep->req_queued); + req = next_request(&dep->started_list); } else { dwc3_prepare_trbs(dep, start_new); /* * req points to the first request where HWO changed from 0 to 1 */ - req = next_request(&dep->req_queued); + req = next_request(&dep->started_list); } if (!req) { dep->flags |= DWC3_EP_PENDING_REQUEST; @@ -962,7 +962,7 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc, { u32 uf; - if (list_empty(&dep->request_list)) { + if (list_empty(&dep->pending_list)) { dwc3_trace(trace_dwc3_gadget, "ISOC ep %s run out for requests", dep->name); @@ -1030,7 +1030,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if (ret) return ret; - list_add_tail(&req->list, &dep->request_list); + list_add_tail(&req->list, &dep->pending_list); /* * If there are no pending requests and the endpoint isn't already @@ -1065,7 +1065,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) * notion of current microframe. */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - if (list_empty(&dep->req_queued)) { + if (list_empty(&dep->started_list)) { dwc3_stop_active_transfer(dwc, dep->number, true); dep->flags = DWC3_EP_ENABLED; } @@ -1183,13 +1183,13 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep, spin_lock_irqsave(&dwc->lock, flags); - list_for_each_entry(r, &dep->request_list, list) { + list_for_each_entry(r, &dep->pending_list, list) { if (r == req) break; } if (r != req) { - list_for_each_entry(r, &dep->req_queued, list) { + list_for_each_entry(r, &dep->started_list, list) { if (r == req) break; } @@ -1229,8 +1229,8 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) if (value) { if (!protocol && ((dep->direction && dep->flags & DWC3_EP_BUSY) || - (!list_empty(&dep->req_queued) || - !list_empty(&dep->request_list)))) { + (!list_empty(&dep->started_list) || + !list_empty(&dep->pending_list)))) { dwc3_trace(trace_dwc3_gadget, "%s: pending request, cannot halt\n", dep->name); @@ -1731,8 +1731,8 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dep->endpoint.caps.dir_in = !!direction; dep->endpoint.caps.dir_out = !direction; - INIT_LIST_HEAD(&dep->request_list); - INIT_LIST_HEAD(&dep->req_queued); + INIT_LIST_HEAD(&dep->pending_list); + INIT_LIST_HEAD(&dep->started_list); } return 0; @@ -1829,11 +1829,11 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, * If there are still queued request * then wait, do not issue either END * or UPDATE TRANSFER, just attach next - * request in request_list during + * request in pending_list during * giveback.If any future queued request * is successfully transferred then we * will issue UPDATE TRANSFER for all - * request in the request_list. + * request in the pending_list. */ dep->flags |= DWC3_EP_MISSED_ISOC; } else { @@ -1879,7 +1879,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, int ret; do { - req = next_request(&dep->req_queued); + req = next_request(&dep->started_list); if (WARN_ON_ONCE(!req)) return 1; @@ -1905,8 +1905,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, } while (1); if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && - list_empty(&dep->req_queued)) { - if (list_empty(&dep->request_list)) { + list_empty(&dep->started_list)) { + if (list_empty(&dep->pending_list)) { /* * If there is no entry in request list then do * not issue END TRANSFER now. Just set PENDING @@ -1955,7 +1955,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, if (!(dep->flags & DWC3_EP_ENABLED)) continue; - if (!list_empty(&dep->req_queued)) + if (!list_empty(&dep->started_list)) return; } diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 18ae3eaa8b6f..f21c0fccbebd 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -68,12 +68,12 @@ static inline struct dwc3_request *next_request(struct list_head *list) return list_first_entry(list, struct dwc3_request, list); } -static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req) +static inline void dwc3_gadget_move_started_request(struct dwc3_request *req) { struct dwc3_ep *dep = req->dep; - req->queued = true; - list_move_tail(&req->list, &dep->req_queued); + req->started = true; + list_move_tail(&req->list, &dep->started_list); } void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, From 46cdd1900fa7a1d7afd1f8d051e513105d0cea98 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 29 Mar 2016 12:26:06 +0300 Subject: [PATCH 05/57] usb: gadget: udc: at91: use PTR_ERR_OR_ZERO() coccicheck found this pattern which could be converted to PTR_ERR_OR_ZERO(). No functional changes. Acked-by: Nicolas Ferre Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/at91_udc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c index d0d18947f58b..8bc78418d40e 100644 --- a/drivers/usb/gadget/udc/at91_udc.c +++ b/drivers/usb/gadget/udc/at91_udc.c @@ -1726,10 +1726,7 @@ static int at91sam9261_udc_init(struct at91_udc *udc) udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node, "atmel,matrix"); - if (IS_ERR(udc->matrix)) - return PTR_ERR(udc->matrix); - - return 0; + return PTR_ERR_OR_ZERO(udc->matrix); } static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on) From acd877f4ec69639c825725091eb3749d36fd11b3 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 29 Mar 2016 12:27:14 +0300 Subject: [PATCH 06/57] usb: phy: qcom: use PTR_ERR_OR_ZERO() coccicheck found this pattern which could be converted to PTR_ERR_OR_ZERO(). No functional changes. Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-qcom-8x16-usb.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c index 3d7af85aecb9..d8593adb3621 100644 --- a/drivers/usb/phy/phy-qcom-8x16-usb.c +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -240,10 +240,7 @@ static int phy_8x16_read_devicetree(struct phy_8x16 *qphy) qphy->switch_gpio = devm_gpiod_get_optional(dev, "switch", GPIOD_OUT_LOW); - if (IS_ERR(qphy->switch_gpio)) - return PTR_ERR(qphy->switch_gpio); - - return 0; + return PTR_ERR_OR_ZERO(qphy->switch_gpio); } static int phy_8x16_reboot_notify(struct notifier_block *this, From 660e9bde74d6915227d7ee3485b11e5f52637b26 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 30 Mar 2016 09:26:24 +0300 Subject: [PATCH 07/57] usb: dwc3: remove num_event_buffers We never, ever route any of the other event buffers so we might as well drop support for them. Until someone has a real, proper benefit for multiple event buffers, we will rely on a single one. This also helps reduce memory footprint of dwc3.ko which won't allocate memory for the extra event buffers. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 77 +++++++++++++++------------------------ drivers/usb/dwc3/core.h | 2 - drivers/usb/dwc3/gadget.c | 38 ++++++------------- 3 files changed, 42 insertions(+), 75 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 67d183a18baa..9e5c57c7943d 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -203,13 +203,10 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, static void dwc3_free_event_buffers(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - int i; - for (i = 0; i < dwc->num_event_buffers; i++) { - evt = dwc->ev_buffs[i]; - if (evt) - dwc3_free_one_event_buffer(dwc, evt); - } + evt = dwc->ev_buffs[0]; + if (evt) + dwc3_free_one_event_buffer(dwc, evt); } /** @@ -222,27 +219,19 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) */ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) { - int num; - int i; + struct dwc3_event_buffer *evt; - num = DWC3_NUM_INT(dwc->hwparams.hwparams1); - dwc->num_event_buffers = num; - - dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num, + dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs), GFP_KERNEL); if (!dwc->ev_buffs) return -ENOMEM; - for (i = 0; i < num; i++) { - struct dwc3_event_buffer *evt; - - evt = dwc3_alloc_one_event_buffer(dwc, length); - if (IS_ERR(evt)) { - dev_err(dwc->dev, "can't allocate event buffer\n"); - return PTR_ERR(evt); - } - dwc->ev_buffs[i] = evt; + evt = dwc3_alloc_one_event_buffer(dwc, length); + if (IS_ERR(evt)) { + dev_err(dwc->dev, "can't allocate event buffer\n"); + return PTR_ERR(evt); } + dwc->ev_buffs[0] = evt; return 0; } @@ -256,25 +245,22 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) static int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - int n; - for (n = 0; n < dwc->num_event_buffers; n++) { - evt = dwc->ev_buffs[n]; - dwc3_trace(trace_dwc3_core, - "Event buf %p dma %08llx length %d\n", - evt->buf, (unsigned long long) evt->dma, - evt->length); + evt = dwc->ev_buffs[0]; + dwc3_trace(trace_dwc3_core, + "Event buf %p dma %08llx length %d\n", + evt->buf, (unsigned long long) evt->dma, + evt->length); - evt->lpos = 0; + evt->lpos = 0; - dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), - lower_32_bits(evt->dma)); - dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), - upper_32_bits(evt->dma)); - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), - DWC3_GEVNTSIZ_SIZE(evt->length)); - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); - } + dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), + lower_32_bits(evt->dma)); + dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), + upper_32_bits(evt->dma)); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), + DWC3_GEVNTSIZ_SIZE(evt->length)); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); return 0; } @@ -282,19 +268,16 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc) static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - int n; - for (n = 0; n < dwc->num_event_buffers; n++) { - evt = dwc->ev_buffs[n]; + evt = dwc->ev_buffs[0]; - evt->lpos = 0; + evt->lpos = 0; - dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), DWC3_GEVNTSIZ_INTMASK - | DWC3_GEVNTSIZ_SIZE(0)); - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0); - } + dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0); + dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK + | DWC3_GEVNTSIZ_SIZE(0)); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 0); } static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4ea4b51688c1..be03999e2dfd 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -667,7 +667,6 @@ struct dwc3_scratchpad_array { * @regs: base address for our registers * @regs_size: address space size * @nr_scratch: number of scratch buffers - * @num_event_buffers: calculated number of event buffers * @u1u2: only used on revisions <1.83a for workaround * @maximum_speed: maximum speed requested (mainly for testing purposes) * @revision: revision register contents @@ -778,7 +777,6 @@ struct dwc3 { u32 gctl; u32 nr_scratch; - u32 num_event_buffers; u32 u1u2; u32 maximum_speed; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e6bd3a976ad9..5e6a4956655d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2602,14 +2602,14 @@ static void dwc3_process_event_entry(struct dwc3 *dwc, } } -static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) +static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; irqreturn_t ret = IRQ_NONE; int left; u32 reg; - evt = dwc->ev_buffs[buf]; + evt = dwc->ev_buffs[0]; left = evt->count; if (!(evt->flags & DWC3_EVENT_PENDING)) @@ -2634,7 +2634,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE; left -= 4; - dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4); + dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 4); } evt->count = 0; @@ -2642,9 +2642,9 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf) ret = IRQ_HANDLED; /* Unmask interrupt */ - reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0)); reg &= ~DWC3_GEVNTSIZ_INTMASK; - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); return ret; } @@ -2654,27 +2654,23 @@ static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) struct dwc3 *dwc = _dwc; unsigned long flags; irqreturn_t ret = IRQ_NONE; - int i; spin_lock_irqsave(&dwc->lock, flags); - - for (i = 0; i < dwc->num_event_buffers; i++) - ret |= dwc3_process_event_buf(dwc, i); - + ret = dwc3_process_event_buf(dwc); spin_unlock_irqrestore(&dwc->lock, flags); return ret; } -static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) +static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; u32 count; u32 reg; - evt = dwc->ev_buffs[buf]; + evt = dwc->ev_buffs[0]; - count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf)); + count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); count &= DWC3_GEVNTCOUNT_MASK; if (!count) return IRQ_NONE; @@ -2683,9 +2679,9 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) evt->flags |= DWC3_EVENT_PENDING; /* Mask interrupt */ - reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(buf)); + reg = dwc3_readl(dwc->regs, DWC3_GEVNTSIZ(0)); reg |= DWC3_GEVNTSIZ_INTMASK; - dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(buf), reg); + dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg); return IRQ_WAKE_THREAD; } @@ -2693,18 +2689,8 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc, u32 buf) static irqreturn_t dwc3_interrupt(int irq, void *_dwc) { struct dwc3 *dwc = _dwc; - int i; - irqreturn_t ret = IRQ_NONE; - for (i = 0; i < dwc->num_event_buffers; i++) { - irqreturn_t status; - - status = dwc3_check_event_buf(dwc, i); - if (status == IRQ_WAKE_THREAD) - ret = status; - } - - return ret; + return dwc3_check_event_buf(dwc); } /** From 696c8b1282205caa5206264449f80ef756f14ef7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 30 Mar 2016 09:37:03 +0300 Subject: [PATCH 08/57] usb: dwc3: drop ev_buffs array we will be using a single event buffer and that renders ev_buffs array unnecessary. Let's remove it in favor of a single pointer to a single event buffer. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 13 ++++--------- drivers/usb/dwc3/core.h | 2 +- drivers/usb/dwc3/gadget.c | 4 ++-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 9e5c57c7943d..05b7ec30266f 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -204,7 +204,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - evt = dwc->ev_buffs[0]; + evt = dwc->ev_buf; if (evt) dwc3_free_one_event_buffer(dwc, evt); } @@ -221,17 +221,12 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) { struct dwc3_event_buffer *evt; - dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs), - GFP_KERNEL); - if (!dwc->ev_buffs) - return -ENOMEM; - evt = dwc3_alloc_one_event_buffer(dwc, length); if (IS_ERR(evt)) { dev_err(dwc->dev, "can't allocate event buffer\n"); return PTR_ERR(evt); } - dwc->ev_buffs[0] = evt; + dwc->ev_buf = evt; return 0; } @@ -246,7 +241,7 @@ static int dwc3_event_buffers_setup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - evt = dwc->ev_buffs[0]; + evt = dwc->ev_buf; dwc3_trace(trace_dwc3_core, "Event buf %p dma %08llx length %d\n", evt->buf, (unsigned long long) evt->dma, @@ -269,7 +264,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) { struct dwc3_event_buffer *evt; - evt = dwc->ev_buffs[0]; + evt = dwc->ev_buf; evt->lpos = 0; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index be03999e2dfd..df72234a805b 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -753,7 +753,7 @@ struct dwc3 { struct platform_device *xhci; struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; - struct dwc3_event_buffer **ev_buffs; + struct dwc3_event_buffer *ev_buf; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; struct usb_gadget gadget; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5e6a4956655d..96dfde011c76 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2609,7 +2609,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc) int left; u32 reg; - evt = dwc->ev_buffs[0]; + evt = dwc->ev_buf; left = evt->count; if (!(evt->flags & DWC3_EVENT_PENDING)) @@ -2668,7 +2668,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc) u32 count; u32 reg; - evt = dwc->ev_buffs[0]; + evt = dwc->ev_buf; count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); count &= DWC3_GEVNTCOUNT_MASK; From dea520a4a28307034b1842adbfde947e1ed385d2 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 30 Mar 2016 09:39:34 +0300 Subject: [PATCH 09/57] usb: dwc3: gadget: pass ev_buff as cookie to irq handler we don't plan on using multiple event buffers, but if we find a good use case for it, this little trick will help us avoid a loop in hardirq handler looping for each and every event buffer. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 96dfde011c76..93b96fffe0e4 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1536,7 +1536,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, irq = platform_get_irq(to_platform_device(dwc->dev), 0); ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt, - IRQF_SHARED, "dwc3", dwc); + IRQF_SHARED, "dwc3", dwc->ev_buf); if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); @@ -1636,7 +1636,7 @@ err2: err1: spin_unlock_irqrestore(&dwc->lock, flags); - free_irq(irq, dwc); + free_irq(irq, dwc->ev_buf); err0: return ret; @@ -1659,7 +1659,7 @@ static int dwc3_gadget_stop(struct usb_gadget *g) spin_unlock_irqrestore(&dwc->lock, flags); irq = platform_get_irq(to_platform_device(dwc->dev), 0); - free_irq(irq, dwc); + free_irq(irq, dwc->ev_buf); return 0; } @@ -2602,14 +2602,13 @@ static void dwc3_process_event_entry(struct dwc3 *dwc, } } -static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc) +static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt) { - struct dwc3_event_buffer *evt; + struct dwc3 *dwc = evt->dwc; irqreturn_t ret = IRQ_NONE; int left; u32 reg; - evt = dwc->ev_buf; left = evt->count; if (!(evt->flags & DWC3_EVENT_PENDING)) @@ -2649,27 +2648,26 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc) return ret; } -static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc) +static irqreturn_t dwc3_thread_interrupt(int irq, void *_evt) { - struct dwc3 *dwc = _dwc; + struct dwc3_event_buffer *evt = _evt; + struct dwc3 *dwc = evt->dwc; unsigned long flags; irqreturn_t ret = IRQ_NONE; spin_lock_irqsave(&dwc->lock, flags); - ret = dwc3_process_event_buf(dwc); + ret = dwc3_process_event_buf(evt); spin_unlock_irqrestore(&dwc->lock, flags); return ret; } -static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc) +static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt) { - struct dwc3_event_buffer *evt; + struct dwc3 *dwc = evt->dwc; u32 count; u32 reg; - evt = dwc->ev_buf; - count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0)); count &= DWC3_GEVNTCOUNT_MASK; if (!count) @@ -2686,11 +2684,11 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3 *dwc) return IRQ_WAKE_THREAD; } -static irqreturn_t dwc3_interrupt(int irq, void *_dwc) +static irqreturn_t dwc3_interrupt(int irq, void *_evt) { - struct dwc3 *dwc = _dwc; + struct dwc3_event_buffer *evt = _evt; - return dwc3_check_event_buf(dwc); + return dwc3_check_event_buf(evt); } /** From badf6d47f8a93098c6e05fdeb735b44b61877451 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 23 Mar 2016 17:45:08 +0100 Subject: [PATCH 10/57] usb: common: rework CONFIG_USB_COMMON logic The phy-am335x driver selects 'USB_COMMON', but all other drivers use 'depends on' for that symbol, and it depends on USB || USB_GADGET itself, which causes a Kconfig warning: warning: (AM335X_PHY_USB) selects USB_COMMON which has unmet direct dependencies (USB_SUPPORT && (USB || USB_GADGET)) As suggested by Felipe Balbi, this turns the logic around, and makes 'USB_COMMON' selected by everything else that needs it, so we can remove the dependencies. Fixes: 59f042f644c5 ("usb: phy: phy-am335x: bypass first VBUS sensing for host-only mode") Signed-off-by: Arnd Bergmann Acked-by: Felipe Balbi Reviewed-by: Peter Chen Signed-off-by: Felipe Balbi --- drivers/phy/Kconfig | 3 ++- drivers/usb/Kconfig | 3 +-- drivers/usb/gadget/Kconfig | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 26566db09de0..e92b97cd6056 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -250,7 +250,8 @@ config PHY_SUN9I_USB tristate "Allwinner sun9i SoC USB PHY driver" depends on ARCH_SUNXI && HAS_IOMEM && OF depends on RESET_CONTROLLER - depends on USB_COMMON + depends on USB_SUPPORT + select USB_COMMON select GENERIC_PHY help Enable this to support the transceiver that is part of Allwinner diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 8ed451dd651e..8689dcba5201 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -31,8 +31,6 @@ if USB_SUPPORT config USB_COMMON tristate - default y - depends on USB || USB_GADGET config USB_ARCH_HAS_HCD def_bool y @@ -41,6 +39,7 @@ config USB_ARCH_HAS_HCD config USB tristate "Support for Host-side USB" depends on USB_ARCH_HAS_HCD + select USB_COMMON select NLS # for UTF-8 strings ---help--- Universal Serial Bus (USB) is a specification for a serial bus diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index af5d922a8f5d..2057add439f0 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -15,6 +15,7 @@ menuconfig USB_GADGET tristate "USB Gadget Support" + select USB_COMMON select NLS help USB is a master/slave protocol, organized with one master From 5e3bd45f170b43cec3fb85f14ef94f176235c4af Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:34 +0200 Subject: [PATCH 11/57] usb: gadged: pch_udc: PCI core handles power state for us There is no need to repeat the work that is already done in the PCI driver core. The patch removes excerpts from suspend and resume callbacks. Note that there is no more calls performed to enable or disable a PCI device during suspend-resume cycle. Nowadays they seems to be superfluous. Someone can read more in [1]. While here, convert PM ops to use modern API. [1] https://www.kernel.org/doc/ols/2009/ols2009-pages-319-330.pdf Signed-off-by: Andy Shevchenko [felipe.balbi@linux.intel.com: fixed build break and checkpatch error ] Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 39 ++++++++++---------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 9571ef54b86b..58fc0adacd79 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -3096,44 +3096,28 @@ static void pch_udc_remove(struct pci_dev *pdev) kfree(dev); } -#ifdef CONFIG_PM -static int pch_udc_suspend(struct pci_dev *pdev, pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int pch_udc_suspend(struct device *d) { + struct pci_dev *pdev = to_pci_dev(d); struct pch_udc_dev *dev = pci_get_drvdata(pdev); pch_udc_disable_interrupts(dev, UDC_DEVINT_MSK); pch_udc_disable_ep_interrupts(dev, UDC_EPINT_MSK_DISABLE_ALL); - pci_disable_device(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - - if (pci_save_state(pdev)) { - dev_err(&pdev->dev, - "%s: could not save PCI config state\n", __func__); - return -ENOMEM; - } - pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; } -static int pch_udc_resume(struct pci_dev *pdev) +static int pch_udc_resume(struct device *d) { - int ret; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "%s: pci_enable_device failed\n", __func__); - return ret; - } - pci_enable_wake(pdev, PCI_D3hot, 0); return 0; } + +static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume); +#define PCH_UDC_PM_OPS (&pch_udc_pm) #else -#define pch_udc_suspend NULL -#define pch_udc_resume NULL -#endif /* CONFIG_PM */ +#define PCH_UDC_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ static int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -3262,9 +3246,10 @@ static struct pci_driver pch_udc_driver = { .id_table = pch_udc_pcidev_id, .probe = pch_udc_probe, .remove = pch_udc_remove, - .suspend = pch_udc_suspend, - .resume = pch_udc_resume, .shutdown = pch_udc_shutdown, + .driver = { + .pm = PCH_UDC_PM_OPS, + }, }; module_pci_driver(pch_udc_driver); From 969733f3768528ce7fb435e90adcb5f7984316ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:35 +0200 Subject: [PATCH 12/57] usb: gadget: pch_udc: convert to devres API devres API allows to make error paths cleaner and less error prone. Convert the driver to use it. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 98 +++++++++----------------------- 1 file changed, 26 insertions(+), 72 deletions(-) diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 58fc0adacd79..82e01f8995c5 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -325,11 +325,8 @@ struct pch_vbus_gpio_data { * @pdev: reference to the PCI device * @ep: array of endpoints * @lock: protects all state - * @active: enabled the PCI device * @stall: stall requested * @prot_stall: protcol stall requested - * @irq_registered: irq registered with system - * @mem_region: device memory mapped * @registered: driver registered with system * @suspended: driver in suspended state * @connected: gadget driver associated @@ -339,12 +336,8 @@ struct pch_vbus_gpio_data { * @data_requests: DMA pool for data requests * @stp_requests: DMA pool for setup requests * @dma_addr: DMA pool for received - * @ep0out_buf: Buffer for DMA * @setup_data: Received setup data - * @phys_addr: of device memory * @base_addr: for mapped device memory - * @bar: Indicates which PCI BAR for USB regs - * @irq: IRQ line for the device * @cfg_data: current cfg, intf, and alt in use * @vbus_gpio: GPIO informaton for detecting VBUS */ @@ -354,11 +347,9 @@ struct pch_udc_dev { struct pci_dev *pdev; struct pch_udc_ep ep[PCH_UDC_EP_NUM]; spinlock_t lock; /* protects all state */ - unsigned active:1, + unsigned stall:1, prot_stall:1, - irq_registered:1, - mem_region:1, suspended:1, connected:1, vbus_session:1, @@ -367,12 +358,8 @@ struct pch_udc_dev { struct pci_pool *data_requests; struct pci_pool *stp_requests; dma_addr_t dma_addr; - void *ep0out_buf; struct usb_ctrlrequest setup_data; - unsigned long phys_addr; void __iomem *base_addr; - unsigned bar; - unsigned irq; struct pch_udc_cfg_data cfg_data; struct pch_vbus_gpio_data vbus_gpio; }; @@ -2949,6 +2936,7 @@ static int init_dma_pools(struct pch_udc_dev *dev) { struct pch_udc_stp_dma_desc *td_stp; struct pch_udc_data_dma_desc *td_data; + void *ep0out_buf; /* DMA setup */ dev->data_requests = pci_pool_create("data_requests", dev->pdev, @@ -2991,10 +2979,11 @@ static int init_dma_pools(struct pch_udc_dev *dev) dev->ep[UDC_EP0IN_IDX].td_data = NULL; dev->ep[UDC_EP0IN_IDX].td_data_phys = 0; - dev->ep0out_buf = kzalloc(UDC_EP0OUT_BUFF_SIZE * 4, GFP_KERNEL); - if (!dev->ep0out_buf) + ep0out_buf = devm_kzalloc(&dev->pdev->dev, UDC_EP0OUT_BUFF_SIZE * 4, + GFP_KERNEL); + if (!ep0out_buf) return -ENOMEM; - dev->dma_addr = dma_map_single(&dev->pdev->dev, dev->ep0out_buf, + dev->dma_addr = dma_map_single(&dev->pdev->dev, ep0out_buf, UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); return 0; @@ -3078,22 +3067,10 @@ static void pch_udc_remove(struct pci_dev *pdev) if (dev->dma_addr) dma_unmap_single(&dev->pdev->dev, dev->dma_addr, UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE); - kfree(dev->ep0out_buf); pch_vbus_gpio_free(dev); pch_udc_exit(dev); - - if (dev->irq_registered) - free_irq(pdev->irq, dev); - if (dev->base_addr) - iounmap(dev->base_addr); - if (dev->mem_region) - release_mem_region(dev->phys_addr, - pci_resource_len(pdev, dev->bar)); - if (dev->active) - pci_disable_device(pdev); - kfree(dev); } #ifdef CONFIG_PM_SLEEP @@ -3122,69 +3099,46 @@ static SIMPLE_DEV_PM_OPS(pch_udc_pm, pch_udc_suspend, pch_udc_resume); static int pch_udc_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - unsigned long resource; - unsigned long len; + int bar; int retval; struct pch_udc_dev *dev; /* init */ - dev = kzalloc(sizeof *dev, GFP_KERNEL); - if (!dev) { - pr_err("%s: no memory for device structure\n", __func__); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) return -ENOMEM; - } + /* pci setup */ - if (pci_enable_device(pdev) < 0) { - kfree(dev); - pr_err("%s: pci_enable_device failed\n", __func__); - return -ENODEV; - } - dev->active = 1; + retval = pcim_enable_device(pdev); + if (retval) + return retval; + pci_set_drvdata(pdev, dev); /* Determine BAR based on PCI ID */ if (id->device == PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC) - dev->bar = PCH_UDC_PCI_BAR_QUARK_X1000; + bar = PCH_UDC_PCI_BAR_QUARK_X1000; else - dev->bar = PCH_UDC_PCI_BAR; + bar = PCH_UDC_PCI_BAR; /* PCI resource allocation */ - resource = pci_resource_start(pdev, dev->bar); - len = pci_resource_len(pdev, dev->bar); + retval = pcim_iomap_regions(pdev, 1 << bar, pci_name(pdev)); + if (retval) + return retval; - if (!request_mem_region(resource, len, KBUILD_MODNAME)) { - dev_err(&pdev->dev, "%s: pci device used already\n", __func__); - retval = -EBUSY; - goto finished; - } - dev->phys_addr = resource; - dev->mem_region = 1; + dev->base_addr = pcim_iomap_table(pdev)[bar]; - dev->base_addr = ioremap_nocache(resource, len); - if (!dev->base_addr) { - pr_err("%s: device memory cannot be mapped\n", __func__); - retval = -ENOMEM; - goto finished; - } - if (!pdev->irq) { - dev_err(&pdev->dev, "%s: irq not set\n", __func__); - retval = -ENODEV; - goto finished; - } /* initialize the hardware */ - if (pch_udc_pcd_init(dev)) { - retval = -ENODEV; - goto finished; - } - if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME, - dev)) { + if (pch_udc_pcd_init(dev)) + return -ENODEV; + + retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (retval) { dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__, pdev->irq); - retval = -ENODEV; goto finished; } - dev->irq = pdev->irq; - dev->irq_registered = 1; pci_set_master(pdev); pci_try_set_mwi(pdev); From c7b640d2a21c2dd724cd8aa9f0b78d6a3d61d776 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:36 +0200 Subject: [PATCH 13/57] usb: gadget: pch_udc: enable MSI if hardware supports Try to enable MSI in case hardware supports it. At least Intel Quark is known SoC which indeed does. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 82e01f8995c5..787f459e9e90 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -3132,6 +3132,8 @@ static int pch_udc_probe(struct pci_dev *pdev, if (pch_udc_pcd_init(dev)) return -ENODEV; + pci_enable_msi(pdev); + retval = devm_request_irq(&pdev->dev, pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME, dev); if (retval) { From 6b968737c3efe7cdaa5407afec972cd7c7d3ca35 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:37 +0200 Subject: [PATCH 14/57] usb: gadged: pch_udc: get rid of redundant assignments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems there are leftovers of some assignments which are not used anymore. Compiler even warns us about: drivers/usb/gadget/udc/pch_udc.c:2022:22: warning: variable ‘dev’ set \ but not used [-Wunused-but-set-variable] drivers/usb/gadget/udc/pch_udc.c:2639:9: warning: variable ‘ret’ set \ but not used [-Wunused-but-set-variable] Remove them and shut compiler about. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 787f459e9e90..d6d1418bdd63 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -1719,14 +1719,12 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if ((usbep->name == ep0_string) || !ep->ep.desc) return -EINVAL; @@ -1757,12 +1755,10 @@ static struct usb_request *pch_udc_alloc_request(struct usb_ep *usbep, struct pch_udc_request *req; struct pch_udc_ep *ep; struct pch_udc_data_dma_desc *dma_desc; - struct pch_udc_dev *dev; if (!usbep) return NULL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; req = kzalloc(sizeof *req, gfp); if (!req) return NULL; @@ -1935,12 +1931,10 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, { struct pch_udc_ep *ep; struct pch_udc_request *req; - struct pch_udc_dev *dev; unsigned long flags; int ret = -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!usbep || !usbreq || (!ep->ep.desc && ep->num)) return ret; req = container_of(usbreq, struct pch_udc_request, req); @@ -1972,14 +1966,12 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; int ret; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) @@ -2017,14 +2009,12 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) static int pch_udc_pcd_set_wedge(struct usb_ep *usbep) { struct pch_udc_ep *ep; - struct pch_udc_dev *dev; unsigned long iflags; int ret; if (!usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); - dev = ep->dev; if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) @@ -2634,7 +2624,7 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev) static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) { u32 reg, dev_stat = 0; - int i, ret; + int i; dev_stat = pch_udc_read_device_status(dev); dev->cfg_data.cur_intf = (dev_stat & UDC_DEVSTS_INTF_MASK) >> @@ -2663,7 +2653,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) } dev->stall = 0; spin_lock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + dev->driver->setup(&dev->gadget, &dev->setup_data); spin_unlock(&dev->lock); } @@ -2674,7 +2664,7 @@ static void pch_udc_svc_intf_interrupt(struct pch_udc_dev *dev) */ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) { - int i, ret; + int i; u32 reg, dev_stat = 0; dev_stat = pch_udc_read_device_status(dev); @@ -2700,7 +2690,7 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev) /* call gadget zero with setup data received */ spin_lock(&dev->lock); - ret = dev->driver->setup(&dev->gadget, &dev->setup_data); + dev->driver->setup(&dev->gadget, &dev->setup_data); spin_unlock(&dev->lock); } From e4875bd4829c1a945bc4714ca806a823a169f3a1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Mar 2016 16:55:38 +0200 Subject: [PATCH 15/57] usb: gadget: pch_udc: sort IDs Sort IDs in groups to be easily found when needed. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index d6d1418bdd63..b2b70d4e2f5b 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -367,8 +367,10 @@ struct pch_udc_dev { #define PCH_UDC_PCI_BAR_QUARK_X1000 0 #define PCH_UDC_PCI_BAR 1 -#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 + #define PCI_DEVICE_ID_INTEL_QUARK_X1000_UDC 0x0939 +#define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 + #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D #define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 From c0ca324d09a041ab56be1aaeb5a7cc64c47f877b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 4 Apr 2016 09:11:51 +0300 Subject: [PATCH 16/57] usb: dwc3: gadget: combine return points into a single one dwc3_send_gadget_ep_cmd() had three return points. That becomes a pain to track when we need to debug something or if we need to add more code before returning. Let's combine all three return points into a single one just by introducing a local 'ret' variable. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 93b96fffe0e4..eb760b275004 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -227,6 +227,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, struct dwc3_ep *dep = dwc->eps[ep]; u32 timeout = 500; u32 reg; + int ret = -EINVAL; trace_dwc3_gadget_ep_cmd(dep, cmd, params); @@ -242,8 +243,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, "Command Complete --> %d", DWC3_DEPCMD_STATUS(reg)); if (DWC3_DEPCMD_STATUS(reg)) - return -EINVAL; - return 0; + break; + ret = 0; + break; } /* @@ -254,11 +256,14 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, if (!timeout) { dwc3_trace(trace_dwc3_gadget, "Command Timed Out"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + break; } udelay(1); } while (1); + + return ret; } static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, From 2b0f11df84bb66c9ac71395382c018f33c3ff9a4 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 4 Apr 2016 09:19:17 +0300 Subject: [PATCH 17/57] usb: dwc3: gadget: clear SUSPHY bit before ep cmds Synopsys Databook 2.60a has a note that if we're sending an endpoint command we _must_ make sure that DWC3_GUSB2PHY(n).SUSPHY bit is cleared. This patch implements that particular detail. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index eb760b275004..79aad1061cdc 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -227,10 +227,27 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, struct dwc3_ep *dep = dwc->eps[ep]; u32 timeout = 500; u32 reg; + + int susphy = false; int ret = -EINVAL; trace_dwc3_gadget_ep_cmd(dep, cmd, params); + /* + * Synopsys Databook 2.60a states, on section 6.3.2.5.[1-8], that if + * we're issuing an endpoint command, we must check if + * GUSB2PHYCFG.SUSPHY bit is set. If it is, then we need to clear it. + * + * We will also set SUSPHY bit to what it was before returning as stated + * by the same section on Synopsys databook. + */ + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) { + susphy = true; + reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2); @@ -263,6 +280,12 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, udelay(1); } while (1); + if (unlikely(susphy)) { + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)); + reg |= DWC3_GUSB2PHYCFG_SUSPHY; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); + } + return ret; } From 218ef7b647e3367c9f81e18f63fbb0066f10b9a5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 4 Apr 2016 11:24:04 +0300 Subject: [PATCH 18/57] usb: dwc3: gadget: extract unlocked dwc3_gadget_wakeup() we will need this from StartTransfer to make sure link is in U0 before starting a transfer. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 79aad1061cdc..2cc2c1545f49 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1361,22 +1361,16 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) return DWC3_DSTS_SOFFN(reg); } -static int dwc3_gadget_wakeup(struct usb_gadget *g) +static int __dwc3_gadget_wakeup(struct dwc3 *dwc) { - struct dwc3 *dwc = gadget_to_dwc(g); - unsigned long timeout; - unsigned long flags; + int ret; u32 reg; - int ret = 0; - u8 link_state; u8 speed; - spin_lock_irqsave(&dwc->lock, flags); - /* * According to the Databook Remote wakeup request should * be issued only when the device is in early suspend state. @@ -1389,8 +1383,7 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) if ((speed == DWC3_DSTS_SUPERSPEED) || (speed == DWC3_DSTS_SUPERSPEED_PLUS)) { dwc3_trace(trace_dwc3_gadget, "no wakeup on SuperSpeed\n"); - ret = -EINVAL; - goto out; + return -EINVAL; } link_state = DWC3_DSTS_USBLNKST(reg); @@ -1403,14 +1396,13 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) dwc3_trace(trace_dwc3_gadget, "can't wakeup from '%s'\n", dwc3_gadget_link_string(link_state)); - ret = -EINVAL; - goto out; + return -EINVAL; } ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); if (ret < 0) { dev_err(dwc->dev, "failed to put link in Recovery\n"); - goto out; + return ret; } /* Recent versions do this automatically */ @@ -1434,10 +1426,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) { dev_err(dwc->dev, "failed to send remote wakeup\n"); - ret = -EINVAL; + return -EINVAL; } -out: + return 0; +} + +static int dwc3_gadget_wakeup(struct usb_gadget *g) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + int ret; + + spin_lock_irqsave(&dwc->lock, flags); + ret = __dwc3_gadget_wakeup(dwc); spin_unlock_irqrestore(&dwc->lock, flags); return ret; From c36d8e947a56a6e6478fc48152c5f4626462db55 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 4 Apr 2016 12:46:33 +0300 Subject: [PATCH 19/57] usb: dwc3: gadget: put link to U0 before Start Transfer Synopsys Databook says we should move link to U0 before issuing a Start Transfer command. We could require the gadget driver to call usb_gadget_wakeup() however I feel that changing all gadget drivers to keep track of Link State and conditionally call usb_gadget_wakeup() would be far too much work. For now we will handle this at the UDC level, but at some point composite.c should be one handling this. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 2cc2c1545f49..0e271584e4cf 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -221,6 +221,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param) } while (1); } +static int __dwc3_gadget_wakeup(struct dwc3 *dwc); + int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) { @@ -248,6 +250,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); } + if (cmd == DWC3_DEPCMD_STARTTRANSFER) { + int needs_wakeup; + + needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 || + dwc->link_state == DWC3_LINK_STATE_U2 || + dwc->link_state == DWC3_LINK_STATE_U3); + + if (unlikely(needs_wakeup)) { + ret = __dwc3_gadget_wakeup(dwc); + dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n", + ret); + } + } + dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1); dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2); From 2c0b98ff29a7452edbbdc503857b74cfaa536808 Mon Sep 17 00:00:00 2001 From: Rajesh Bhagat Date: Mon, 14 Mar 2016 14:40:51 +0530 Subject: [PATCH 20/57] Documentation: dt: dwc3: Add snps,dis_rxdet_inp3_quirk property Add snps,dis_rxdet_inp3_quirk property which disables receiver detection in PHY P3 power state. Signed-off-by: Sriram Dash Signed-off-by: Rajesh Bhagat Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index 15695682a480..7d7ce089b003 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -37,6 +37,8 @@ Optional properties: - snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy. - snps,dis_enblslpm_quirk: when set clears the enblslpm in GUSB2PHYCFG, disabling the suspend signal to the PHY. + - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection + in PHY P3 power state. - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal utmi_l1_suspend_n, false when asserts utmi_sleep_n - snps,hird-threshold: HIRD threshold From e58dd357741b93f5bc5487aabba968c76bb099ef Mon Sep 17 00:00:00 2001 From: Rajesh Bhagat Date: Mon, 14 Mar 2016 14:40:50 +0530 Subject: [PATCH 21/57] usb: dwc3: add disable receiver detection in P3 quirk Some freescale QorIQ platforms require to disable receiver detection in P3 for correct detection of USB devices. If GUSB3PIPECTL(DISRXDETINP3) is set, Core will change PHY power state to P2 and then perform receiver detection. After receiver detection, Core will change PHY power state to P3. Same quirk would be added in dts file in future patches. Signed-off-by: Sriram Dash Signed-off-by: Rajesh Bhagat Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 2 ++ drivers/usb/dwc3/platform_data.h | 1 + 3 files changed, 9 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 05b7ec30266f..940489c1d1bd 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -412,6 +412,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->u2ss_inp3_quirk) reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK; + if (dwc->dis_rxdet_inp3_quirk) + reg |= DWC3_GUSB3PIPECTL_DISRXDETINP3; + if (dwc->req_p1p2p3_quirk) reg |= DWC3_GUSB3PIPECTL_REQP1P2P3; @@ -882,6 +885,8 @@ static int dwc3_probe(struct platform_device *pdev) "snps,dis_u2_susphy_quirk"); dwc->dis_enblslpm_quirk = device_property_read_bool(dev, "snps,dis_enblslpm_quirk"); + dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev, + "snps,dis_rxdet_inp3_quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); @@ -915,6 +920,7 @@ static int dwc3_probe(struct platform_device *pdev) dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk; dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk; + dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk; dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; if (pdata->tx_de_emphasis) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index df72234a805b..f965e961b40e 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -193,6 +193,7 @@ /* Global USB3 PIPE Control Register */ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) +#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28) #define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24) #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) @@ -867,6 +868,7 @@ struct dwc3 { unsigned dis_u3_susphy_quirk:1; unsigned dis_u2_susphy_quirk:1; unsigned dis_enblslpm_quirk:1; + unsigned dis_rxdet_inp3_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h index aaa6f00df755..8826cca5fc6f 100644 --- a/drivers/usb/dwc3/platform_data.h +++ b/drivers/usb/dwc3/platform_data.h @@ -42,6 +42,7 @@ struct dwc3_platform_data { unsigned dis_u3_susphy_quirk:1; unsigned dis_u2_susphy_quirk:1; unsigned dis_enblslpm_quirk:1; + unsigned dis_rxdet_inp3_quirk:1; unsigned tx_de_emphasis_quirk:1; unsigned tx_de_emphasis:2; From 495dd5f78145c44274eeb8ec297195ac71a8fed0 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 5 Apr 2016 15:09:44 +0300 Subject: [PATCH 22/57] usb: dwc3: omap: drop dma_mask configuration The DWC3 OMAP driver supports DT-boot only, as result dma_mask will be always configured properly from DT - of_platform_device_create_pdata()->of_dma_configure(). More over, dwc3-omap.c can be built as module and in this case it's unsafe to assign local variable as dma_mask. Hence, remove dma_mask configuration code. Signed-off-by: Grygorii Strashko Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 22e9606d8e08..e92a992c2255 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -331,8 +331,6 @@ static void dwc3_omap_disable_irqs(struct dwc3_omap *omap) dwc3_omap_write_irqmisc_clr(omap, reg); } -static u64 dwc3_omap_dma_mask = DMA_BIT_MASK(32); - static int dwc3_omap_id_notifier(struct notifier_block *nb, unsigned long event, void *ptr) { @@ -490,7 +488,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) omap->irq = irq; omap->base = base; omap->vbus_reg = vbus_reg; - dev->dma_mask = &dwc3_omap_dma_mask; pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); From 53fd88189e08c91cb9b43e2d51b4eb314a3d00d7 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 4 Apr 2016 15:33:41 +0300 Subject: [PATCH 23/57] usb: dwc3: gadget: rename busy/free_slot to trb_enqueue/dequeue This makes it clear that we're dealing with a queue of TRBs. No functional changes. While at that, also rename start_slot to first_trb_index for similar reasons. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 10 +++++----- drivers/usb/dwc3/ep0.c | 6 +++--- drivers/usb/dwc3/gadget.c | 30 +++++++++++++++--------------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f965e961b40e..a29d797bfcf4 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -449,8 +449,8 @@ struct dwc3_event_buffer { * @started_list: list of started requests on this endpoint * @trb_pool: array of transaction buffers * @trb_pool_dma: dma address of @trb_pool - * @free_slot: next slot which is going to be used - * @busy_slot: first slot which is owned by HW + * @trb_enqueue: enqueue 'pointer' into TRB array + * @trb_dequeue: dequeue 'pointer' into TRB array * @desc: usb_endpoint_descriptor pointer * @dwc: pointer to DWC controller * @saved_state: ep state saved during hibernation @@ -470,8 +470,8 @@ struct dwc3_ep { struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; - u32 free_slot; - u32 busy_slot; + u32 trb_enqueue; + u32 trb_dequeue; const struct usb_ss_ep_comp_descriptor *comp_desc; struct dwc3 *dwc; @@ -628,7 +628,7 @@ struct dwc3_request { struct usb_request request; struct list_head list; struct dwc3_ep *dep; - u32 start_slot; + u32 first_trb_index; u8 epnum; struct dwc3_trb *trb; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 5e0a21b65053..143deb420481 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -70,10 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, return 0; } - trb = &dwc->ep0_trb[dep->free_slot]; + trb = &dwc->ep0_trb[dep->trb_enqueue]; if (chain) - dep->free_slot++; + dep->trb_enqueue++; trb->bpl = lower_32_bits(buf_dma); trb->bph = upper_32_bits(buf_dma); @@ -845,7 +845,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, trb++; length = trb->size & DWC3_TRB_SIZE_MASK; - ep0->free_slot = 0; + ep0->trb_enqueue = 0; } transfer_size = roundup((ur->length - transfer_size), diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0e271584e4cf..bb29f4f08f5d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -154,16 +154,16 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, if (req->started) { i = 0; do { - dep->busy_slot++; + dep->trb_dequeue++; /* * Skip LINK TRB. We can't use req->trb and check for * DWC3_TRBCTL_LINK_TRB because it points the TRB we * just completed (not the LINK TRB). */ - if (((dep->busy_slot & DWC3_TRB_MASK) == + if (((dep->trb_dequeue & DWC3_TRB_MASK) == DWC3_TRB_NUM- 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) - dep->busy_slot++; + dep->trb_dequeue++; } while(++i < req->request.num_mapped_sgs); req->started = false; } @@ -741,20 +741,20 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, chain ? " chain" : ""); - trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; + trb = &dep->trb_pool[dep->trb_enqueue & DWC3_TRB_MASK]; if (!req->trb) { dwc3_gadget_move_started_request(req); req->trb = trb; req->trb_dma = dwc3_trb_dma_offset(dep, trb); - req->start_slot = dep->free_slot & DWC3_TRB_MASK; + req->first_trb_index = dep->trb_enqueue & DWC3_TRB_MASK; } - dep->free_slot++; + dep->trb_enqueue++; /* Skip the LINK-TRB on ISOC */ - if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && + if (((dep->trb_enqueue & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) - dep->free_slot++; + dep->trb_enqueue++; trb->size = DWC3_TRB_SIZE_LENGTH(length); trb->bpl = lower_32_bits(dma); @@ -826,11 +826,11 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); /* the first request must not be queued */ - trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK; + trbs_left = (dep->trb_dequeue - dep->trb_enqueue) & DWC3_TRB_MASK; /* Can't wrap around on a non-isoc EP since there's no link TRB */ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK); + max = DWC3_TRB_NUM - (dep->trb_enqueue & DWC3_TRB_MASK); if (trbs_left > max) trbs_left = max; } @@ -856,11 +856,11 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) * don't wrap around we have to start at the beginning. */ if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - dep->busy_slot = 1; - dep->free_slot = 1; + dep->trb_dequeue = 1; + dep->trb_enqueue = 1; } else { - dep->busy_slot = 0; - dep->free_slot = 0; + dep->trb_dequeue = 0; + dep->trb_enqueue = 0; } } @@ -1931,7 +1931,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, i = 0; do { - slot = req->start_slot + i; + slot = req->first_trb_index + i; if ((slot == DWC3_TRB_NUM - 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) slot++; From 5ef68c56e169a9249b94645a9ea9ca8d14672d26 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 5 Apr 2016 11:33:30 +0300 Subject: [PATCH 24/57] usb: dwc3: core: document struct dwc3_request No functional changes. Merely adding useful documentation for future readers. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index a29d797bfcf4..c0049c811cca 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -624,6 +624,19 @@ struct dwc3_hwparams { /* HWPARAMS7 */ #define DWC3_RAM1_DEPTH(n) ((n) & 0xffff) +/** + * struct dwc3_request - representation of a transfer request + * @request: struct usb_request to be transferred + * @list: a list_head used for request queueing + * @dep: struct dwc3_ep owning this request + * @first_trb_index: index to first trb used by this request + * @epnum: endpoint number to which this request refers + * @trb: pointer to struct dwc3_trb + * @trb_dma: DMA address of @trb + * @direction: IN or OUT direction flag + * @mapped: true when request has been dma-mapped + * @queued: true when request has been queued to HW + */ struct dwc3_request { struct usb_request request; struct list_head list; From c28f82595dde97dda0b769f78f0faea78acd993b Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 5 Apr 2016 12:42:15 +0300 Subject: [PATCH 25/57] usb: dwc3: switch trb enqueue/dequeue and first_trb_index to u8 We *know* that we have 1 PAGE (4096 bytes) for our TRB poll. We also know the size of each TRB and know that we can fit 256 of them in one PAGE. By using a u8 type we can make sure that: enqueue++ % 256; gets optimized to an increment only. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index c0049c811cca..2f19573e08d9 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -470,8 +470,6 @@ struct dwc3_ep { struct dwc3_trb *trb_pool; dma_addr_t trb_pool_dma; - u32 trb_enqueue; - u32 trb_dequeue; const struct usb_ss_ep_comp_descriptor *comp_desc; struct dwc3 *dwc; @@ -487,6 +485,18 @@ struct dwc3_ep { /* This last one is specific to EP0 */ #define DWC3_EP0_DIR_IN (1 << 31) + /* + * IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will + * use a u8 type here. If anybody decides to increase number of TRBs to + * anything larger than 256 - I can't see why people would want to do + * this though - then this type needs to be changed. + * + * By using u8 types we ensure that our % operator when incrementing + * enqueue and dequeue get optimized away by the compiler. + */ + u8 trb_enqueue; + u8 trb_dequeue; + u8 number; u8 type; u8 resource_index; @@ -641,8 +651,8 @@ struct dwc3_request { struct usb_request request; struct list_head list; struct dwc3_ep *dep; - u32 first_trb_index; + u8 first_trb_index; u8 epnum; struct dwc3_trb *trb; dma_addr_t trb_dma; From 70fdb273db37196e9e5d292d5778a99fededb32f Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 5 Apr 2016 12:47:15 +0300 Subject: [PATCH 26/57] usb: dwc3: get rid of DWC3_TRB_MASK instead of using a bitwise and, let's rely on the % operator since that's a lot more clear. Also, GCC will optimize % 256 to nothing anyway. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 1 - drivers/usb/dwc3/gadget.c | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 2f19573e08d9..832da3f2e03a 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -440,7 +440,6 @@ struct dwc3_event_buffer { #define DWC3_EP_DIRECTION_RX false #define DWC3_TRB_NUM 256 -#define DWC3_TRB_MASK (DWC3_TRB_NUM - 1) /** * struct dwc3_ep - device side endpoint representation diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index bb29f4f08f5d..0e7cc20c2fd0 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -160,8 +160,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, * DWC3_TRBCTL_LINK_TRB because it points the TRB we * just completed (not the LINK TRB). */ - if (((dep->trb_dequeue & DWC3_TRB_MASK) == - DWC3_TRB_NUM- 1) && + if (((dep->trb_dequeue % DWC3_TRB_NUM) == + DWC3_TRB_NUM - 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) dep->trb_dequeue++; } while(++i < req->request.num_mapped_sgs); @@ -741,18 +741,18 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, chain ? " chain" : ""); - trb = &dep->trb_pool[dep->trb_enqueue & DWC3_TRB_MASK]; + trb = &dep->trb_pool[dep->trb_enqueue % DWC3_TRB_NUM]; if (!req->trb) { dwc3_gadget_move_started_request(req); req->trb = trb; req->trb_dma = dwc3_trb_dma_offset(dep, trb); - req->first_trb_index = dep->trb_enqueue & DWC3_TRB_MASK; + req->first_trb_index = dep->trb_enqueue % DWC3_TRB_NUM; } dep->trb_enqueue++; /* Skip the LINK-TRB on ISOC */ - if (((dep->trb_enqueue & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && + if (((dep->trb_enqueue % DWC3_TRB_NUM) == DWC3_TRB_NUM - 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) dep->trb_enqueue++; @@ -826,11 +826,11 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); /* the first request must not be queued */ - trbs_left = (dep->trb_dequeue - dep->trb_enqueue) & DWC3_TRB_MASK; + trbs_left = (dep->trb_dequeue - dep->trb_enqueue) % DWC3_TRB_NUM; /* Can't wrap around on a non-isoc EP since there's no link TRB */ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - max = DWC3_TRB_NUM - (dep->trb_enqueue & DWC3_TRB_MASK); + max = DWC3_TRB_NUM - (dep->trb_enqueue % DWC3_TRB_NUM); if (trbs_left > max) trbs_left = max; } From ef966b9d33533b0bf01fb8c4d586ac3b20a3bdb5 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 5 Apr 2016 13:09:51 +0300 Subject: [PATCH 27/57] usb: dwc3: gadget: add trb enqueue/dequeue helpers Add three little helpers which will aid in making the code slightly easier to read. One helper increments enqueue pointer, another increments dequeue pointer and the last one tests if we're dealing with the last TRB. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0e7cc20c2fd0..98d8a4549103 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -145,6 +145,21 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) return -ETIMEDOUT; } +static void dwc3_ep_inc_enq(struct dwc3_ep *dep) +{ + dep->trb_enqueue++; +} + +static void dwc3_ep_inc_deq(struct dwc3_ep *dep) +{ + dep->trb_dequeue++; +} + +static int dwc3_ep_is_last_trb(unsigned int index) +{ + return (index % DWC3_TRB_NUM) == (DWC3_TRB_NUM - 1); +} + void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status) { @@ -154,16 +169,15 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, if (req->started) { i = 0; do { - dep->trb_dequeue++; + dwc3_ep_inc_deq(dep); /* * Skip LINK TRB. We can't use req->trb and check for * DWC3_TRBCTL_LINK_TRB because it points the TRB we * just completed (not the LINK TRB). */ - if (((dep->trb_dequeue % DWC3_TRB_NUM) == - DWC3_TRB_NUM - 1) && + if (dwc3_ep_is_last_trb(dep->trb_dequeue) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) - dep->trb_dequeue++; + dwc3_ep_inc_deq(dep); } while(++i < req->request.num_mapped_sgs); req->started = false; } @@ -750,11 +764,11 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, req->first_trb_index = dep->trb_enqueue % DWC3_TRB_NUM; } - dep->trb_enqueue++; + dwc3_ep_inc_enq(dep); /* Skip the LINK-TRB on ISOC */ - if (((dep->trb_enqueue % DWC3_TRB_NUM) == DWC3_TRB_NUM - 1) && + if (dwc3_ep_is_last_trb(dep->trb_enqueue) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) - dep->trb_enqueue++; + dwc3_ep_inc_enq(dep); trb->size = DWC3_TRB_SIZE_LENGTH(length); trb->bpl = lower_32_bits(dma); From 4faf75504a7db790483aa419d8f61e58cec4934c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 5 Apr 2016 13:14:31 +0300 Subject: [PATCH 28/57] usb: dwc3: gadget: move % operation to increment helpers By moving our % DWC3_NUM_TRB operation to the increment helpers, the rest of the driver can be simplified. It's also a good practice to make sure we will have a single place dealing with details about how to increment our enqueue and dequeue pointers. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 98d8a4549103..6c5eb0c59696 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -148,16 +148,18 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state) static void dwc3_ep_inc_enq(struct dwc3_ep *dep) { dep->trb_enqueue++; + dep->trb_enqueue %= DWC3_TRB_NUM; } static void dwc3_ep_inc_deq(struct dwc3_ep *dep) { dep->trb_dequeue++; + dep->trb_dequeue %= DWC3_TRB_NUM; } static int dwc3_ep_is_last_trb(unsigned int index) { - return (index % DWC3_TRB_NUM) == (DWC3_TRB_NUM - 1); + return index == DWC3_TRB_NUM - 1; } void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, @@ -755,13 +757,13 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, chain ? " chain" : ""); - trb = &dep->trb_pool[dep->trb_enqueue % DWC3_TRB_NUM]; + trb = &dep->trb_pool[dep->trb_enqueue]; if (!req->trb) { dwc3_gadget_move_started_request(req); req->trb = trb; req->trb_dma = dwc3_trb_dma_offset(dep, trb); - req->first_trb_index = dep->trb_enqueue % DWC3_TRB_NUM; + req->first_trb_index = dep->trb_enqueue; } dwc3_ep_inc_enq(dep); @@ -840,11 +842,11 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); /* the first request must not be queued */ - trbs_left = (dep->trb_dequeue - dep->trb_enqueue) % DWC3_TRB_NUM; + trbs_left = dep->trb_dequeue - dep->trb_enqueue; /* Can't wrap around on a non-isoc EP since there's no link TRB */ if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - max = DWC3_TRB_NUM - (dep->trb_enqueue % DWC3_TRB_NUM); + max = DWC3_TRB_NUM - dep->trb_enqueue; if (trbs_left > max) trbs_left = max; } From 36b68aae8e39ad456eec1ec2073eee388cbcc106 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 5 Apr 2016 13:24:36 +0300 Subject: [PATCH 29/57] usb: dwc3: gadget: use link TRB for all endpoint types instead of limiting link TRB only to Isoc endpoints, let's use it for all endpoint types, this way we are more likely to transfer more data before a XferComplete event. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 49 ++++++++------------------------------- 1 file changed, 10 insertions(+), 39 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 6c5eb0c59696..5f95008aa730 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -177,8 +177,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, * DWC3_TRBCTL_LINK_TRB because it points the TRB we * just completed (not the LINK TRB). */ - if (dwc3_ep_is_last_trb(dep->trb_dequeue) && - usb_endpoint_xfer_isoc(dep->endpoint.desc)) + if (dwc3_ep_is_last_trb(dep->trb_dequeue)) dwc3_ep_inc_deq(dep); } while(++i < req->request.num_mapped_sgs); req->started = false; @@ -541,10 +540,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, reg |= DWC3_DALEPENA_EP(dep->number); dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); - if (!usb_endpoint_xfer_isoc(desc)) + if (usb_endpoint_xfer_control(desc)) goto out; - /* Link TRB for ISOC. The HWO bit is never reset */ + /* Link TRB. The HWO bit is never reset */ trb_st_hw = &dep->trb_pool[0]; trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1]; @@ -767,9 +766,8 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, } dwc3_ep_inc_enq(dep); - /* Skip the LINK-TRB on ISOC */ - if (dwc3_ep_is_last_trb(dep->trb_enqueue) && - usb_endpoint_xfer_isoc(dep->endpoint.desc)) + /* Skip the LINK-TRB */ + if (dwc3_ep_is_last_trb(dep->trb_enqueue)) dwc3_ep_inc_enq(dep); trb->size = DWC3_TRB_SIZE_LENGTH(length); @@ -836,52 +834,26 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) { struct dwc3_request *req, *n; u32 trbs_left; - u32 max; unsigned int last_one = 0; BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM); - /* the first request must not be queued */ trbs_left = dep->trb_dequeue - dep->trb_enqueue; - /* Can't wrap around on a non-isoc EP since there's no link TRB */ - if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - max = DWC3_TRB_NUM - dep->trb_enqueue; - if (trbs_left > max) - trbs_left = max; - } - /* - * If busy & slot are equal than it is either full or empty. If we are - * starting to process requests then we are empty. Otherwise we are + * If enqueue & dequeue are equal than it is either full or empty. If we + * are starting to process requests then we are empty. Otherwise we are * full and don't do anything */ if (!trbs_left) { if (!starting) return; + trbs_left = DWC3_TRB_NUM; - /* - * In case we start from scratch, we queue the ISOC requests - * starting from slot 1. This is done because we use ring - * buffer and have no LST bit to stop us. Instead, we place - * IOC bit every TRB_NUM/4. We try to avoid having an interrupt - * after the first request so we start at slot 1 and have - * 7 requests proceed before we hit the first IOC. - * Other transfer types don't use the ring buffer and are - * processed from the first TRB until the last one. Since we - * don't wrap around we have to start at the beginning. - */ - if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { - dep->trb_dequeue = 1; - dep->trb_enqueue = 1; - } else { - dep->trb_dequeue = 0; - dep->trb_enqueue = 0; - } } /* The last TRB is a link TRB, not used for xfer */ - if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) + if (trbs_left <= 1) return; list_for_each_entry_safe(req, n, &dep->pending_list, list) { @@ -1948,8 +1920,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, i = 0; do { slot = req->first_trb_index + i; - if ((slot == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->endpoint.desc)) + if (slot == DWC3_TRB_NUM - 1) slot++; slot %= DWC3_TRB_NUM; trb = &dep->trb_pool[slot]; From 052ba52efa1717651d303a9b88f2e8cbb91702c6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 5 Apr 2016 15:05:05 +0300 Subject: [PATCH 30/57] usb: dwc3: gadget: remove newline from trace trace already adds a newline character for us, we don't need to do it ourselves. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5f95008aa730..c068a8f21f37 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1264,7 +1264,7 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) (!list_empty(&dep->started_list) || !list_empty(&dep->pending_list)))) { dwc3_trace(trace_dwc3_gadget, - "%s: pending request, cannot halt\n", + "%s: pending request, cannot halt", dep->name); return -EAGAIN; } From 8e7046b71daeb6dfbf8c6eaa164e55d4e1dcb5c8 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 6 Apr 2016 10:01:14 +0300 Subject: [PATCH 31/57] usb: dwc3: gadget: don't interrupt when chained It makes no sense to interrupt in the middle of chained transfer. This patch just makes sure we don't do that. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index c068a8f21f37..88fd30bf0c46 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -804,7 +804,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, /* always enable Continue on Short Packet */ trb->ctrl |= DWC3_TRB_CTRL_CSP; - if (!req->request.no_interrupt) + if (!req->request.no_interrupt && !chain) trb->ctrl |= DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_ISP_IMI; if (last) From af566a0be6e49b946708532a6a7a7ae29ab83aed Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 11 Apr 2016 17:18:25 +0300 Subject: [PATCH 32/57] usb: dwc3: omap: get rid of dma_status dma_status bit flag is set but never really used so get rid of it. Reported-by: Felipe Balbi Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-omap.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index e92a992c2255..59ea35ffc043 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -126,8 +126,6 @@ struct dwc3_omap { u32 debug_offset; u32 irq0_offset; - u32 dma_status:1; - struct extcon_dev *edev; struct notifier_block vbus_nb; struct notifier_block id_nb; @@ -277,9 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) reg = dwc3_omap_read_irqmisc_status(omap); - if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) - omap->dma_status = false; - dwc3_omap_write_irqmisc_status(omap, reg); reg = dwc3_omap_read_irq0_status(omap); @@ -501,7 +496,6 @@ static int dwc3_omap_probe(struct platform_device *pdev) /* check the DMA Status */ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); - omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE); ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0, "dwc3-omap", omap); From 4e9f311833a946e984c82086b21b128918f4a6a4 Mon Sep 17 00:00:00 2001 From: "Du, Changbin" Date: Tue, 12 Apr 2016 19:10:18 +0800 Subject: [PATCH 33/57] usb: dwc3: make dwc3_debugfs_init return value be void Debugfs init failure is not so important. We can continue our job on this failure. Also no break need for debugfs_create_file call failure. Signed-off-by: Du, Changbin [felipe.balbi@linux.intel.com : - remove out-of-memory message, we get that from OOM. - switch dev_err() to dev_dbg() ] Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 10 +------ drivers/usb/dwc3/debug.h | 6 ++--- drivers/usb/dwc3/debugfs.c | 53 +++++++++++++------------------------- 3 files changed, 22 insertions(+), 47 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 940489c1d1bd..6f57929f09b4 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1030,19 +1030,11 @@ static int dwc3_probe(struct platform_device *pdev) if (ret) goto err5; - ret = dwc3_debugfs_init(dwc); - if (ret) { - dev_err(dev, "failed to initialize debugfs\n"); - goto err6; - } - + dwc3_debugfs_init(dwc); pm_runtime_allow(dev); return 0; -err6: - dwc3_core_exit_mode(dwc); - err5: dwc3_event_buffers_cleanup(dwc); diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 07fbc2d94fd4..71e318025964 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -217,11 +217,11 @@ static inline const char *dwc3_gadget_event_type_string(u8 event) void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...); #ifdef CONFIG_DEBUG_FS -extern int dwc3_debugfs_init(struct dwc3 *); +extern void dwc3_debugfs_init(struct dwc3 *); extern void dwc3_debugfs_exit(struct dwc3 *); #else -static inline int dwc3_debugfs_init(struct dwc3 *d) -{ return 0; } +static inline void dwc3_debugfs_init(struct dwc3 *d) +{ } static inline void dwc3_debugfs_exit(struct dwc3 *d) { } #endif diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 9ac37fe1b6a7..81faddc60c8e 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -618,24 +618,23 @@ static const struct file_operations dwc3_link_state_fops = { .release = single_release, }; -int dwc3_debugfs_init(struct dwc3 *dwc) +void dwc3_debugfs_init(struct dwc3 *dwc) { struct dentry *root; - struct dentry *file; - int ret; + struct dentry *file; root = debugfs_create_dir(dev_name(dwc->dev), NULL); - if (!root) { - ret = -ENOMEM; - goto err0; + if (IS_ERR_OR_NULL(root)) { + if (!root) + dev_err(dwc->dev, "Can't create debugfs root\n"); + return; } - dwc->root = root; dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL); if (!dwc->regset) { - ret = -ENOMEM; - goto err1; + debugfs_remove_recursive(root); + return; } dwc->regset->regs = dwc3_regs; @@ -643,44 +642,28 @@ int dwc3_debugfs_init(struct dwc3 *dwc) dwc->regset->base = dwc->regs; file = debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset); - if (!file) { - ret = -ENOMEM; - goto err1; - } + if (!file) + dev_dbg(dwc->dev, "Can't create debugfs regdump\n"); if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) { file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, dwc, &dwc3_mode_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } + if (!file) + dev_dbg(dwc->dev, "Can't create debugfs mode\n"); } if (IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE) || IS_ENABLED(CONFIG_USB_DWC3_GADGET)) { file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, dwc, &dwc3_testmode_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } + if (!file) + dev_dbg(dwc->dev, "Can't create debugfs testmode\n"); - file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root, - dwc, &dwc3_link_state_fops); - if (!file) { - ret = -ENOMEM; - goto err1; - } + file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, + root, dwc, &dwc3_link_state_fops); + if (!file) + dev_dbg(dwc->dev, "Can't create debugfs link_state\n"); } - - return 0; - -err1: - debugfs_remove_recursive(root); - -err0: - return ret; } void dwc3_debugfs_exit(struct dwc3 *dwc) From 5096c4d3bfa75bdd23c78f799aabd08598afb48f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 Apr 2016 16:53:38 +0900 Subject: [PATCH 34/57] usb: gadget: udc: core: Fix argument of dev_err() in usb_gadget_map_request() The argument of dev_err() in usb_gadget_map_request() should be dev instead of &gadget->dev. Fixes: 7ace8fc ("usb: gadget: udc: core: Fix argument of dma_map_single for IOMMU") Cc: # v4.3+ Signed-off-by: Yoshihiro Shimoda --- drivers/usb/gadget/udc/udc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index e4e70e11d0f6..c6e76465065a 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -75,7 +75,7 @@ int usb_gadget_map_request(struct usb_gadget *gadget, mapped = dma_map_sg(dev, req->sg, req->num_sgs, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); if (mapped == 0) { - dev_err(&gadget->dev, "failed to map SGs\n"); + dev_err(dev, "failed to map SGs\n"); return -EFAULT; } From 679ca39fc670a5a95c2b40d2cc8cf2cee2486f7a Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 Apr 2016 16:53:39 +0900 Subject: [PATCH 35/57] usb: gadget: udc: core: add usb_gadget_{un}map_request_by_dev() If the following environment, the first argument of DMA API should be set to a DMAC's device structure, not a udc controller's one. - A udc controller needs an external DMAC device (like a DMA Engine). - The external DMAC enables IOMMU. So, this patch add usb_gadget_{un}map_request_by_dev() API to set a DMAC's device structure by a udc controller driver. Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/udc-core.c | 24 ++++++++++++++++++------ include/linux/usb/gadget.h | 4 ++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c index c6e76465065a..6e8300d6a737 100644 --- a/drivers/usb/gadget/udc/udc-core.c +++ b/drivers/usb/gadget/udc/udc-core.c @@ -61,11 +61,9 @@ static int udc_bind_to_driver(struct usb_udc *udc, #ifdef CONFIG_HAS_DMA -int usb_gadget_map_request(struct usb_gadget *gadget, +int usb_gadget_map_request_by_dev(struct device *dev, struct usb_request *req, int is_in) { - struct device *dev = gadget->dev.parent; - if (req->length == 0) return 0; @@ -92,24 +90,38 @@ int usb_gadget_map_request(struct usb_gadget *gadget, return 0; } +EXPORT_SYMBOL_GPL(usb_gadget_map_request_by_dev); + +int usb_gadget_map_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + return usb_gadget_map_request_by_dev(gadget->dev.parent, req, is_in); +} EXPORT_SYMBOL_GPL(usb_gadget_map_request); -void usb_gadget_unmap_request(struct usb_gadget *gadget, +void usb_gadget_unmap_request_by_dev(struct device *dev, struct usb_request *req, int is_in) { if (req->length == 0) return; if (req->num_mapped_sgs) { - dma_unmap_sg(gadget->dev.parent, req->sg, req->num_mapped_sgs, + dma_unmap_sg(dev, req->sg, req->num_mapped_sgs, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->num_mapped_sgs = 0; } else { - dma_unmap_single(gadget->dev.parent, req->dma, req->length, + dma_unmap_single(dev, req->dma, req->length, is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } } +EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); + +void usb_gadget_unmap_request(struct usb_gadget *gadget, + struct usb_request *req, int is_in) +{ + usb_gadget_unmap_request_by_dev(gadget->dev.parent, req, is_in); +} EXPORT_SYMBOL_GPL(usb_gadget_unmap_request); #endif /* CONFIG_HAS_DMA */ diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 5d4e151c49bf..457651bf45b0 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -1223,9 +1223,13 @@ int usb_otg_descriptor_init(struct usb_gadget *gadget, /* utility to simplify map/unmap of usb_requests to/from DMA */ +extern int usb_gadget_map_request_by_dev(struct device *dev, + struct usb_request *req, int is_in); extern int usb_gadget_map_request(struct usb_gadget *gadget, struct usb_request *req, int is_in); +extern void usb_gadget_unmap_request_by_dev(struct device *dev, + struct usb_request *req, int is_in); extern void usb_gadget_unmap_request(struct usb_gadget *gadget, struct usb_request *req, int is_in); From e789ece1823596f24076aed1b9a2182a81b0a6b7 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 Apr 2016 16:53:40 +0900 Subject: [PATCH 36/57] usb: renesas_usbhs: change function call orfer in usbhsf_dma_prepare_push() Since usbhsf_dma_{un}map() will use the "fifo" data in the near future, this patch changes function call orfer in usbhsf_dma_prepare_push(). Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/fifo.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 000f9750149f..a805b239e805 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -881,12 +881,12 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) if (!fifo) goto usbhsf_pio_prepare_push; - if (usbhsf_dma_map(pkt) < 0) - goto usbhsf_pio_prepare_push; - ret = usbhsf_fifo_select(pipe, fifo, 0); if (ret < 0) - goto usbhsf_pio_prepare_push_unmap; + goto usbhsf_pio_prepare_push; + + if (usbhsf_dma_map(pkt) < 0) + goto usbhsf_pio_prepare_push_unselect; pkt->trans = len; @@ -896,8 +896,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) return 0; -usbhsf_pio_prepare_push_unmap: - usbhsf_dma_unmap(pkt); +usbhsf_pio_prepare_push_unselect: + usbhsf_fifo_unselect(pipe, fifo); usbhsf_pio_prepare_push: /* * change handler to PIO From c3cdcac786ae8ce9221a05609952d14aa57c27f7 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 Apr 2016 16:53:41 +0900 Subject: [PATCH 37/57] usb: renesas_usbhs: change arguments of dma_map_ctrl() Since usbhsg_dma_map_ctrl() needs DMA device structure in the near future, this patch changes arguments of dma_map_ctrl() to give such data. (This patch is only change the argument.) Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/fifo.c | 4 +++- drivers/usb/renesas_usbhs/mod_gadget.c | 3 ++- drivers/usb/renesas_usbhs/mod_host.c | 3 ++- drivers/usb/renesas_usbhs/pipe.c | 3 ++- drivers/usb/renesas_usbhs/pipe.h | 6 ++++-- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index a805b239e805..7be4e7d57ace 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -799,8 +799,10 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map) struct usbhs_pipe *pipe = pkt->pipe; struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe); + struct dma_chan *chan = usbhsf_dma_chan_get(fifo, pkt); - return info->dma_map_ctrl(pkt, map); + return info->dma_map_ctrl(chan->device->dev, pkt, map); } static void usbhsf_dma_complete(void *arg); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 53d104b56ef1..d701ae643ace 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -191,7 +191,8 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep, /* * dma map/unmap */ -static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map) +static int usbhsg_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt, + int map) { struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); struct usb_request *req = &ureq->req; diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 1a8e4c45c4c5..3bf0b72eb359 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -929,7 +929,8 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, /* * dma map functions */ -static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map) +static int usbhsh_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt, + int map) { if (map) { struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 78e9dba701c4..77b615ce4a25 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -655,7 +655,8 @@ static void usbhsp_put_pipe(struct usbhs_pipe *pipe) } void usbhs_pipe_init(struct usbhs_priv *priv, - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)) + int (*dma_map_ctrl)(struct device *dma_dev, + struct usbhs_pkt *pkt, int map)) { struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); struct usbhs_pipe *pipe; diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index 7835747f9803..95185fdb29b1 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -47,7 +47,8 @@ struct usbhs_pipe_info { struct usbhs_pipe *pipe; int size; /* array size of "pipe" */ - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map); + int (*dma_map_ctrl)(struct device *dma_dev, struct usbhs_pkt *pkt, + int map); }; /* @@ -84,7 +85,8 @@ int usbhs_pipe_is_running(struct usbhs_pipe *pipe); void usbhs_pipe_running(struct usbhs_pipe *pipe, int running); void usbhs_pipe_init(struct usbhs_priv *priv, - int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)); + int (*dma_map_ctrl)(struct device *dma_dev, + struct usbhs_pkt *pkt, int map)); int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe); void usbhs_pipe_clear(struct usbhs_pipe *pipe); int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); From b41d8a6a014fba420a428244e04699b9c77a44f1 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 18 Apr 2016 16:53:42 +0900 Subject: [PATCH 38/57] usb: renesas_usbhs: use usb_gadget_{un}map_request_by_dev() for IPMMU The previous code could use the first USB-DMAC with IPMMU if iommus property was set into this device node. However, in this case, it could not control the second USB-DMAC with IPMMU because a parameter of IPMMU (micro-TLB id) is different with each USB-DMAC. So, this patch uses the usb_gadget_{un}map_request_by_dev() APIs for IPMMU. (Then, iommus property should be set into USB-DMAC node(s).) Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/mod_gadget.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index d701ae643ace..30345c2d01be 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -197,8 +197,6 @@ static int usbhsg_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt, struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt); struct usb_request *req = &ureq->req; struct usbhs_pipe *pipe = pkt->pipe; - struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe); - struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); enum dma_data_direction dir; int ret = 0; @@ -208,13 +206,13 @@ static int usbhsg_dma_map_ctrl(struct device *dma_dev, struct usbhs_pkt *pkt, /* it can not use scatter/gather */ WARN_ON(req->num_sgs); - ret = usb_gadget_map_request(&gpriv->gadget, req, dir); + ret = usb_gadget_map_request_by_dev(dma_dev, req, dir); if (ret < 0) return ret; pkt->dma = req->dma; } else { - usb_gadget_unmap_request(&gpriv->gadget, req, dir); + usb_gadget_unmap_request_by_dev(dma_dev, req, dir); } return ret; From 9bc07890f891267285716c09bfee58e239137d36 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Apr 2016 15:05:12 +0200 Subject: [PATCH 39/57] usb: gadget: r8a66597-udc: Deinline pipe_change, save 2176 bytes This function compiles to 298 bytes of machine code, has ~10 callsites. This is a USB 2.0 device, USB 2.0 is limited to ~40 MB/s, so should be almost never CPU bound. No need to optimize for speed this agressively. Signed-off-by: Denys Vlasenko CC: Felipe Balbi CC: linux-usb@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/r8a66597-udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index baa0609a429d..8b300e6da7fc 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -296,7 +296,7 @@ static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum, } while ((tmp & mask) != loop); } -static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) +static void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) { struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; From 332a5b446b7916d272c2a659a3b20909ce34d2c1 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 30 Mar 2016 13:49:14 +0200 Subject: [PATCH 40/57] usb: gadget: f_fs: Fix EFAULT generation for async read operations In the current implementation functionfs generates a EFAULT for async read operations if the read buffer size is larger than the URB data size. Since a application does not necessarily know how much data the host side is going to send it typically supplies a buffer larger than the actual data, which will then result in a EFAULT error. This behaviour was introduced while refactoring the code to use iov_iter interface in commit c993c39b8639 ("gadget/function/f_fs.c: use put iov_iter into io_data"). The original code took the minimum over the URB size and the user buffer size and then attempted to copy that many bytes using copy_to_user(). If copy_to_user() could not copy all data a EFAULT error was generated. Restore the original behaviour by only generating a EFAULT error when the number of bytes copied is not the size of the URB and the target buffer has not been fully filled. Commit 342f39a6c8d3 ("usb: gadget: f_fs: fix check in read operation") already fixed the same problem for the synchronous read path. Fixes: c993c39b8639 ("gadget/function/f_fs.c: use put iov_iter into io_data") Acked-by: Michal Nazarewicz Signed-off-by: Lars-Peter Clausen Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index e21ca2bd6839..2c314c13f9a7 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -650,7 +650,7 @@ static void ffs_user_copy_worker(struct work_struct *work) if (io_data->read && ret > 0) { use_mm(io_data->mm); ret = copy_to_iter(io_data->buf, ret, &io_data->data); - if (iov_iter_count(&io_data->data)) + if (ret != io_data->req->actual && iov_iter_count(&io_data->data)) ret = -EFAULT; unuse_mm(io_data->mm); } From f78bbcae86e676fad9e6c6bb6cd9d9868ba23696 Mon Sep 17 00:00:00 2001 From: Michal Nazarewicz Date: Fri, 8 Apr 2016 10:24:11 +0200 Subject: [PATCH 41/57] usb: f_mass_storage: test whether thread is running before starting another MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When binding the function to usb_configuration, check whether the thread is running before starting another one. Without that, when function instance is added to multiple configurations, fsg_bing starts multiple threads with all but the latest one being forgotten by the driver. This leads to obvious thread leaks, possible lockups when trying to halt the machine and possible more issues. This fixes issues with legacy/multi¹ gadget as well as configfs gadgets when mass_storage function is added to multiple configurations. This change also simplifies API since the legacy gadgets no longer need to worry about starting the thread by themselves (which was where bug in legacy/multi was in the first place). N.B., this patch doesn’t address adding single mass_storage function instance to a single configuration twice. Thankfully, there’s no legitimate reason for such setup plus, if I’m not mistaken, configfs gadget doesn’t even allow it to be expressed. ¹ I have no example failure though. Conclusion that legacy/multi has a bug is based purely on me reading the code. Acked-by: Alan Stern Signed-off-by: Michal Nazarewicz Tested-by: Ivaylo Dimitrov Cc: Alan Stern Cc: Signed-off-by: Felipe Balbi --- drivers/usb/gadget/function/f_mass_storage.c | 36 ++++++++------------ drivers/usb/gadget/function/f_mass_storage.h | 2 -- drivers/usb/gadget/legacy/acm_ms.c | 4 --- drivers/usb/gadget/legacy/mass_storage.c | 4 --- drivers/usb/gadget/legacy/multi.c | 12 ------- drivers/usb/gadget/legacy/nokia.c | 7 ---- 6 files changed, 15 insertions(+), 50 deletions(-) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index acf210f16328..5c6d4d7ca605 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2977,25 +2977,6 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, } EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); -int fsg_common_run_thread(struct fsg_common *common) -{ - common->state = FSG_STATE_IDLE; - /* Tell the thread to start working */ - common->thread_task = - kthread_create(fsg_main_thread, common, "file-storage"); - if (IS_ERR(common->thread_task)) { - common->state = FSG_STATE_TERMINATED; - return PTR_ERR(common->thread_task); - } - - DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task)); - - wake_up_process(common->thread_task); - - return 0; -} -EXPORT_SYMBOL_GPL(fsg_common_run_thread); - static void fsg_common_release(struct kref *ref) { struct fsg_common *common = container_of(ref, struct fsg_common, ref); @@ -3005,6 +2986,7 @@ static void fsg_common_release(struct kref *ref) if (common->state != FSG_STATE_TERMINATED) { raise_exception(common, FSG_STATE_EXIT); wait_for_completion(&common->thread_notifier); + common->thread_task = NULL; } for (i = 0; i < ARRAY_SIZE(common->luns); ++i) { @@ -3050,9 +3032,21 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f) if (ret) return ret; fsg_common_set_inquiry_string(fsg->common, NULL, NULL); - ret = fsg_common_run_thread(fsg->common); - if (ret) + } + + if (!common->thread_task) { + common->state = FSG_STATE_IDLE; + common->thread_task = + kthread_create(fsg_main_thread, common, "file-storage"); + if (IS_ERR(common->thread_task)) { + int ret = PTR_ERR(common->thread_task); + common->thread_task = NULL; + common->state = FSG_STATE_TERMINATED; return ret; + } + DBG(common, "I/O thread pid: %d\n", + task_pid_nr(common->thread_task)); + wake_up_process(common->thread_task); } fsg->gadget = gadget; diff --git a/drivers/usb/gadget/function/f_mass_storage.h b/drivers/usb/gadget/function/f_mass_storage.h index 445df6775609..b6a9918eaefb 100644 --- a/drivers/usb/gadget/function/f_mass_storage.h +++ b/drivers/usb/gadget/function/f_mass_storage.h @@ -153,8 +153,6 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, const char *pn); -int fsg_common_run_thread(struct fsg_common *common); - void fsg_config_from_params(struct fsg_config *cfg, const struct fsg_module_parameters *params, unsigned int fsg_num_buffers); diff --git a/drivers/usb/gadget/legacy/acm_ms.c b/drivers/usb/gadget/legacy/acm_ms.c index c16089efc322..c39de65a448b 100644 --- a/drivers/usb/gadget/legacy/acm_ms.c +++ b/drivers/usb/gadget/legacy/acm_ms.c @@ -133,10 +133,6 @@ static int acm_ms_do_config(struct usb_configuration *c) if (status < 0) goto put_msg; - status = fsg_common_run_thread(opts->common); - if (status) - goto remove_acm; - status = usb_add_function(c, f_msg); if (status) goto remove_acm; diff --git a/drivers/usb/gadget/legacy/mass_storage.c b/drivers/usb/gadget/legacy/mass_storage.c index e61af53c7d2b..125974f32f50 100644 --- a/drivers/usb/gadget/legacy/mass_storage.c +++ b/drivers/usb/gadget/legacy/mass_storage.c @@ -132,10 +132,6 @@ static int msg_do_config(struct usb_configuration *c) if (IS_ERR(f_msg)) return PTR_ERR(f_msg); - ret = fsg_common_run_thread(opts->common); - if (ret) - goto put_func; - ret = usb_add_function(c, f_msg); if (ret) goto put_func; diff --git a/drivers/usb/gadget/legacy/multi.c b/drivers/usb/gadget/legacy/multi.c index 229d704a620b..a70a406580ea 100644 --- a/drivers/usb/gadget/legacy/multi.c +++ b/drivers/usb/gadget/legacy/multi.c @@ -137,7 +137,6 @@ static struct usb_function *f_msg_rndis; static int rndis_do_config(struct usb_configuration *c) { - struct fsg_opts *fsg_opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -169,11 +168,6 @@ static int rndis_do_config(struct usb_configuration *c) goto err_fsg; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - ret = fsg_common_run_thread(fsg_opts->common); - if (ret) - goto err_run; - ret = usb_add_function(c, f_msg_rndis); if (ret) goto err_run; @@ -225,7 +219,6 @@ static struct usb_function *f_msg_multi; static int cdc_do_config(struct usb_configuration *c) { - struct fsg_opts *fsg_opts; int ret; if (gadget_is_otg(c->cdev->gadget)) { @@ -258,11 +251,6 @@ static int cdc_do_config(struct usb_configuration *c) goto err_fsg; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - ret = fsg_common_run_thread(fsg_opts->common); - if (ret) - goto err_run; - ret = usb_add_function(c, f_msg_multi); if (ret) goto err_run; diff --git a/drivers/usb/gadget/legacy/nokia.c b/drivers/usb/gadget/legacy/nokia.c index 09975046c694..b1e535f4022e 100644 --- a/drivers/usb/gadget/legacy/nokia.c +++ b/drivers/usb/gadget/legacy/nokia.c @@ -152,7 +152,6 @@ static int nokia_bind_config(struct usb_configuration *c) struct usb_function *f_ecm; struct usb_function *f_obex2 = NULL; struct usb_function *f_msg; - struct fsg_opts *fsg_opts; int status = 0; int obex1_stat = -1; int obex2_stat = -1; @@ -222,12 +221,6 @@ static int nokia_bind_config(struct usb_configuration *c) goto err_ecm; } - fsg_opts = fsg_opts_from_func_inst(fi_msg); - - status = fsg_common_run_thread(fsg_opts->common); - if (status) - goto err_msg; - status = usb_add_function(c, f_msg); if (status) goto err_msg; From 097aa1975e9a5b189d4c6fbc95c0f97e2c49c01e Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 18 Apr 2016 12:57:15 +0300 Subject: [PATCH 42/57] usb: gadget: pch_udc: don't free devm allocated memory Coccinelle caught this instance of us kfree()ing devm-allocated memory. The solution is just to not do anything in our gadget_release. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/pch_udc.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index b2b70d4e2f5b..ebc51ec5790a 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -2834,17 +2834,6 @@ static void pch_udc_setup_ep0(struct pch_udc_dev *dev) UDC_DEVINT_SI | UDC_DEVINT_SC); } -/** - * gadget_release() - Free the gadget driver private data - * @pdev reference to struct pci_dev - */ -static void gadget_release(struct device *pdev) -{ - struct pch_udc_dev *dev = dev_get_drvdata(pdev); - - kfree(dev); -} - /** * pch_udc_pcd_reinit() - This API initializes the endpoint structures * @dev: Reference to the driver structure @@ -3151,8 +3140,7 @@ static int pch_udc_probe(struct pci_dev *pdev, /* Put the device in disconnected state till a driver is bound */ pch_udc_set_disconnect(dev); - retval = usb_add_gadget_udc_release(&pdev->dev, &dev->gadget, - gadget_release); + retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); if (retval) goto finished; return 0; From cf6d867d3b57d4eca229b3c506216d98d88be49c Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 14 Apr 2016 15:03:39 +0300 Subject: [PATCH 43/57] usb: dwc3: core: add fifo space helper this helper will be used, initially, to dump space of different queues and fifos in dwc3 to debugfs. Later, it'll be used to issue remote wakeup when we want to start a transfer and there's something in a TX FIFO. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 14 ++++++++++++++ drivers/usb/dwc3/core.h | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 6f57929f09b4..c050a88c16d4 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -60,6 +60,20 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode) dwc3_writel(dwc->regs, DWC3_GCTL, reg); } +u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) +{ + struct dwc3 *dwc = dep->dwc; + u32 reg; + + dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE, + DWC3_GDBGFIFOSPACE_NUM(dep->number) | + DWC3_GDBGFIFOSPACE_TYPE(type)); + + reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE); + + return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg); +} + /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 832da3f2e03a..c3ea4270bf33 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -152,6 +152,19 @@ /* Bit fields */ +/* Global Debug Queue/FIFO Space Available Register */ +#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f) +#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) +#define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff) + +#define DWC3_TXFIFOQ 1 +#define DWC3_RXFIFOQ 3 +#define DWC3_TXREQQ 5 +#define DWC3_RXREQQ 7 +#define DWC3_RXINFOQ 9 +#define DWC3_DESCFETCHQ 13 +#define DWC3_EVENTQ 15 + /* Global Configuration Register */ #define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) #define DWC3_GCTL_U2RSTECN (1 << 16) @@ -1043,6 +1056,7 @@ struct dwc3_gadget_ep_cmd_params { /* prototypes */ void dwc3_set_mode(struct dwc3 *dwc, u32 mode); +u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); /* check whether we are on the DWC_usb31 core */ static inline bool dwc3_is_usb31(struct dwc3 *dwc) From b058f3e8a3991ba3ea3504fea1faf81974cf17fa Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 14 Apr 2016 16:05:54 +0300 Subject: [PATCH 44/57] usb: dwc3: core: add helper to extract trb type This helper will be used later to convert trb type into a human-readable string for debugfs. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index c3ea4270bf33..bbbd1789596e 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -580,6 +580,7 @@ enum dwc3_link_state { #define DWC3_TRB_CTRL_IOC (1 << 11) #define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14) +#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4)) #define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1) #define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2) #define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3) From 818ec3aba883f58225c9f5a2318cf373263869ed Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 14 Apr 2016 14:53:44 +0300 Subject: [PATCH 45/57] usb: dwc3: debugfs: dump out endpoint details There's a bunch of information in the debug register set from dwc3 which is useful in some debugging scenarios. Let's dump them out in endpoint-specific directories and designated files. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/debugfs.c | 302 +++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 81faddc60c8e..6c14f653dc9b 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -618,6 +618,306 @@ static const struct file_operations dwc3_link_state_fops = { .release = single_release, }; +struct dwc3_ep_file_map { + char name[25]; + int (*show)(struct seq_file *s, void *unused); +}; + +static int dwc3_tx_fifo_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_TXFIFOQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_rx_fifo_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_RXFIFOQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_tx_request_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_TXREQQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_rx_request_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_RXREQQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_rx_info_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_RXINFOQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_descriptor_fetch_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_DESCFETCHQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_event_queue_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&dwc->lock, flags); + val = dwc3_core_fifo_space(dep, DWC3_EVENTQ); + seq_printf(s, "%u\n", val); + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static int dwc3_ep_transfer_type_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + if (!(dep->flags & DWC3_EP_ENABLED) || + !dep->endpoint.desc) { + seq_printf(s, "--\n"); + goto out; + } + + switch (usb_endpoint_type(dep->endpoint.desc)) { + case USB_ENDPOINT_XFER_CONTROL: + seq_printf(s, "control\n"); + break; + case USB_ENDPOINT_XFER_ISOC: + seq_printf(s, "isochronous\n"); + break; + case USB_ENDPOINT_XFER_BULK: + seq_printf(s, "bulk\n"); + break; + case USB_ENDPOINT_XFER_INT: + seq_printf(s, "interrupt\n"); + break; + default: + seq_printf(s, "--\n"); + } + +out: + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb) +{ + switch (DWC3_TRBCTL_TYPE(trb->ctrl)) { + case DWC3_TRBCTL_NORMAL: + return "normal"; + case DWC3_TRBCTL_CONTROL_SETUP: + return "control-setup"; + case DWC3_TRBCTL_CONTROL_STATUS2: + return "control-status2"; + case DWC3_TRBCTL_CONTROL_STATUS3: + return "control-status3"; + case DWC3_TRBCTL_CONTROL_DATA: + return "control-data"; + case DWC3_TRBCTL_ISOCHRONOUS_FIRST: + return "isoc-first"; + case DWC3_TRBCTL_ISOCHRONOUS: + return "isoc"; + case DWC3_TRBCTL_LINK_TRB: + return "link"; + default: + return "UNKNOWN"; + } +} + +static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused) +{ + struct dwc3_ep *dep = s->private; + struct dwc3 *dwc = dep->dwc; + unsigned long flags; + int i; + + spin_lock_irqsave(&dwc->lock, flags); + if (dep->number <= 1) { + seq_printf(s, "--\n"); + goto out; + } + + seq_printf(s, "enqueue pointer %d\n", dep->trb_enqueue); + seq_printf(s, "dequeue pointer %d\n", dep->trb_dequeue); + seq_printf(s, "\n--------------------------------------------------\n\n"); + seq_printf(s, "buffer_addr,size,type,ioc,isp_imi,csp,chn,lst,hwo\n"); + + for (i = 0; i < DWC3_TRB_NUM; i++) { + struct dwc3_trb *trb = &dep->trb_pool[i]; + + seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n", + trb->bph, trb->bpl, trb->size, + dwc3_trb_type_string(trb), + !!(trb->ctrl & DWC3_TRB_CTRL_IOC), + !!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI), + !!(trb->ctrl & DWC3_TRB_CTRL_CSP), + !!(trb->ctrl & DWC3_TRB_CTRL_CHN), + !!(trb->ctrl & DWC3_TRB_CTRL_LST), + !!(trb->ctrl & DWC3_TRB_CTRL_HWO)); + } + +out: + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + +static struct dwc3_ep_file_map map[] = { + { "tx_fifo_queue", dwc3_tx_fifo_queue_show, }, + { "rx_fifo_queue", dwc3_rx_fifo_queue_show, }, + { "tx_request_queue", dwc3_tx_request_queue_show, }, + { "rx_request_queue", dwc3_rx_request_queue_show, }, + { "rx_info_queue", dwc3_rx_info_queue_show, }, + { "descriptor_fetch_queue", dwc3_descriptor_fetch_queue_show, }, + { "event_queue", dwc3_event_queue_show, }, + { "transfer_type", dwc3_ep_transfer_type_show, }, + { "trb_ring", dwc3_ep_trb_ring_show, }, +}; + +static int dwc3_endpoint_open(struct inode *inode, struct file *file) +{ + const char *file_name = file_dentry(file)->d_iname; + struct dwc3_ep_file_map *f_map; + int i; + + for (i = 0; i < ARRAY_SIZE(map); i++) { + f_map = &map[i]; + + if (strcmp(f_map->name, file_name) == 0) + break; + } + + return single_open(file, f_map->show, inode->i_private); +} + +static const struct file_operations dwc3_endpoint_fops = { + .open = dwc3_endpoint_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void dwc3_debugfs_create_endpoint_file(struct dwc3_ep *dep, + struct dentry *parent, int type) +{ + struct dentry *file; + struct dwc3_ep_file_map *ep_file = &map[type]; + + file = debugfs_create_file(ep_file->name, S_IRUGO, parent, dep, + &dwc3_endpoint_fops); +} + +static void dwc3_debugfs_create_endpoint_files(struct dwc3_ep *dep, + struct dentry *parent) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(map); i++) + dwc3_debugfs_create_endpoint_file(dep, parent, i); +} + +static void dwc3_debugfs_create_endpoint_dir(struct dwc3_ep *dep, + struct dentry *parent) +{ + struct dentry *dir; + + dir = debugfs_create_dir(dep->name, parent); + if (IS_ERR_OR_NULL(dir)) + return; + + dwc3_debugfs_create_endpoint_files(dep, dir); +} + +static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc, + struct dentry *parent) +{ + int i; + + for (i = 0; i < dwc->num_in_eps; i++) { + u8 epnum = (i << 1) | 1; + struct dwc3_ep *dep = dwc->eps[epnum]; + + if (!dep) + continue; + + dwc3_debugfs_create_endpoint_dir(dep, parent); + } + + for (i = 0; i < dwc->num_out_eps; i++) { + u8 epnum = (i << 1); + struct dwc3_ep *dep = dwc->eps[epnum]; + + if (!dep) + continue; + + dwc3_debugfs_create_endpoint_dir(dep, parent); + } +} + void dwc3_debugfs_init(struct dwc3 *dwc) { struct dentry *root; @@ -663,6 +963,8 @@ void dwc3_debugfs_init(struct dwc3 *dwc) root, dwc, &dwc3_link_state_fops); if (!file) dev_dbg(dwc->dev, "Can't create debugfs link_state\n"); + + dwc3_debugfs_create_endpoint_dirs(dwc, root); } } From ae411413760785a0a2ce6cb44d5afe95115aa24d Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Wed, 20 Apr 2016 09:08:43 +0300 Subject: [PATCH 46/57] usb: dwc3: ep0: sanity check test mode selector In case host sends us an unsupported test mode, we *must* stall this request. This will tell the host that the selector is invalid and we won't put the controller in unsupported test modes which could have undetermined side-effects. Signed-off-by: Fei Yang Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/ep0.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 143deb420481..51b52a79dfec 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -463,8 +463,18 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, if (!set) return -EINVAL; - dwc->test_mode_nr = wIndex >> 8; - dwc->test_mode = true; + switch (wIndex >> 8) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + case TEST_FORCE_EN: + dwc->test_mode_nr = wIndex >> 8; + dwc->test_mode = true; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; From 474799f073763b868e158b04b74f8ddd1da38da2 Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 22 Apr 2016 11:17:37 +0300 Subject: [PATCH 47/57] usb: dwc3: pci: make build-in device properties available Setting the ACPI companion before calling dwc3_pci_quirks. The ACPI companion will be set unconditionally as the primary fwnode, overriding any previously set primary fwnode. This will make sure that any build-in properties added to the platform device will be added as the secondary fwnode in cases where also ACPI companion exists. Signed-off-by: Heikki Krogerus Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index adc1e8a624cb..e444e9a1a0c8 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -170,13 +170,14 @@ static int dwc3_pci_probe(struct pci_dev *pci, } pci_set_drvdata(pci, dwc3); - ret = dwc3_pci_quirks(pci); - if (ret) - goto err; dwc3->dev.parent = dev; ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev)); + ret = dwc3_pci_quirks(pci); + if (ret) + goto err; + ret = platform_device_add(dwc3); if (ret) { dev_err(dev, "failed to register dwc3 device\n"); From ce046d323d74ee9d280688a2cb499716f555a89f Mon Sep 17 00:00:00 2001 From: Heikki Krogerus Date: Fri, 22 Apr 2016 11:17:38 +0300 Subject: [PATCH 48/57] usb: dwc3: pci: pass the platform device as a parameter to dwc3_pci_quirks() For convenience, passing the dwc3 platform device as a parameter to dwc3_pci_quirks() function. Signed-off-by: Heikki Krogerus Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/dwc3-pci.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index e444e9a1a0c8..14196cd416b3 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -47,7 +47,7 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = { { }, }; -static int dwc3_pci_quirks(struct pci_dev *pdev) +static int dwc3_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc3) { if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == PCI_DEVICE_ID_AMD_NL_USB) { @@ -77,8 +77,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) pdata.dis_u3_susphy_quirk = true; pdata.dis_u2_susphy_quirk = true; - return platform_device_add_data(pci_get_drvdata(pdev), &pdata, - sizeof(pdata)); + return platform_device_add_data(dwc3, &pdata, sizeof(pdata)); } if (pdev->vendor == PCI_VENDOR_ID_INTEL && @@ -123,8 +122,7 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) pdata.has_lpm_erratum = true; pdata.dis_enblslpm_quirk = true; - return platform_device_add_data(pci_get_drvdata(pdev), &pdata, - sizeof(pdata)); + return platform_device_add_data(dwc3, &pdata, sizeof(pdata)); } return 0; @@ -169,12 +167,10 @@ static int dwc3_pci_probe(struct pci_dev *pci, return ret; } - pci_set_drvdata(pci, dwc3); - dwc3->dev.parent = dev; ACPI_COMPANION_SET(&dwc3->dev, ACPI_COMPANION(dev)); - ret = dwc3_pci_quirks(pci); + ret = dwc3_pci_quirks(pci, dwc3); if (ret) goto err; @@ -184,6 +180,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, goto err; } + pci_set_drvdata(pci, dwc3); return 0; err: platform_device_put(dwc3); From 0878263b68df372e6389b050fc2bd4f6d5b9f332 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 22 Apr 2016 14:53:47 +0300 Subject: [PATCH 49/57] usb: gadget: composite: avoid kernel oops with bad gadgets If a gadget driver loaded to a Superspeed-capable peripheral controller, using a Superspeed cable, doesn't provide Superspeed descriptors, we will get a NULL pointer dereference. In order to avoid that situation, we will try to find any valid descriptors we can. If no set of descriptors is passed in, then we'll let that gadget oops anyhow. Signed-off-by: Felipe Balbi --- drivers/usb/gadget/composite.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index de9ffd60fcfa..3d3cdc5ed20d 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -66,20 +66,36 @@ function_descriptors(struct usb_function *f, { struct usb_descriptor_header **descriptors; + /* + * NOTE: we try to help gadget drivers which might not be setting + * max_speed appropriately. + */ + switch (speed) { case USB_SPEED_SUPER_PLUS: descriptors = f->ssp_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ case USB_SPEED_SUPER: descriptors = f->ss_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ case USB_SPEED_HIGH: descriptors = f->hs_descriptors; - break; + if (descriptors) + break; + /* FALLTHROUGH */ default: descriptors = f->fs_descriptors; } + /* + * if we can't find any descriptors at all, then this gadget deserves to + * Oops with a NULL pointer dereference + */ + return descriptors; } From 7b9cc7a2b101cc73f6abe3468441381c98817e54 Mon Sep 17 00:00:00 2001 From: Konrad Leszczynski Date: Fri, 12 Feb 2016 15:21:46 +0000 Subject: [PATCH 50/57] usb: dwc3: gadget: give better command return code if Start Transfer command fails, let's try a little harder to figure out why the command failed and give slightly better return codes. This will be usefulf or isochronous endpoints, at least, which could decide to retry a given request. Signed-off-by: Konrad Leszczynski Signed-off-by: Rafal Redzimski Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 4 ++++ drivers/usb/dwc3/gadget.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index bbbd1789596e..87df6dd20d23 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -970,6 +970,10 @@ struct dwc3_event_depevt { #define DEPEVT_STATUS_CONTROL_DATA 1 #define DEPEVT_STATUS_CONTROL_STATUS 2 +/* In response to Start Transfer */ +#define DEPEVT_TRANSFER_NO_RESOURCE 1 +#define DEPEVT_TRANSFER_BUS_EXPIRY 2 + u32 parameters:16; } __packed; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 88fd30bf0c46..43efb627d1cf 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -287,12 +287,39 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, do { reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep)); if (!(reg & DWC3_DEPCMD_CMDACT)) { + int cmd_status = DWC3_DEPCMD_STATUS(reg); + dwc3_trace(trace_dwc3_gadget, "Command Complete --> %d", - DWC3_DEPCMD_STATUS(reg)); - if (DWC3_DEPCMD_STATUS(reg)) + cmd_status); + + switch (cmd_status) { + case 0: + ret = 0; break; - ret = 0; + case DEPEVT_TRANSFER_NO_RESOURCE: + dwc3_trace(trace_dwc3_gadget, "%s: no resource available"); + ret = -EINVAL; + break; + case DEPEVT_TRANSFER_BUS_EXPIRY: + /* + * SW issues START TRANSFER command to + * isochronous ep with future frame interval. If + * future interval time has already passed when + * core receives the command, it will respond + * with an error status of 'Bus Expiry'. + * + * Instead of always returning -EINVAL, let's + * give a hint to the gadget driver that this is + * the case by returning -EAGAIN. + */ + dwc3_trace(trace_dwc3_gadget, "%s: bus expiry"); + ret = -EAGAIN; + break; + default: + dev_WARN(dwc->dev, "UNKNOWN cmd status\n"); + } + break; } From 8c3d609275f7f39d308e5c40a6220c67454f7a28 Mon Sep 17 00:00:00 2001 From: Vahram Aharonyan Date: Wed, 27 Apr 2016 20:20:46 -0700 Subject: [PATCH 51/57] usb: dwc2: gadget: Check for ep0 in enable Replaced the WARN_ON with a check and return of -EINVAL in the dwc2_hsotg_ep_enable function if ep0 is passed in. Signed-off-by: Vahram Aharonyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 818f158232bb..d330190f58ef 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2631,7 +2631,10 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, desc->wMaxPacketSize, desc->bInterval); /* not to be called for EP0 */ - WARN_ON(index == 0); + if (index == 0) { + dev_err(hsotg->dev, "%s: called for EP 0\n", __func__); + return -EINVAL; + } dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0; if (dir_in != hs_ep->dir_in) { From ee3de8d750134703c702534173cd8623d1b32c38 Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 27 Apr 2016 20:20:48 -0700 Subject: [PATCH 52/57] usb: dwc2: gadget: Prevent handling of host interrupts In host slave mode, the core asserts the rxready, txfifoempty interrupts that get serviced in the gadget irq handler. Prevent servicing of these when not in the gadget mode of operation. Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/gadget.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index d330190f58ef..4c5e3005e1dc 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -2425,6 +2425,9 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw) u32 gintsts; u32 gintmsk; + if (!dwc2_is_device_mode(hsotg)) + return IRQ_NONE; + spin_lock(&hsotg->lock); irq_retry: gintsts = dwc2_readl(hsotg->regs + GINTSTS); From b0d659022e5c96ee5c4bd62d22d3da2d66de306b Mon Sep 17 00:00:00 2001 From: Vardan Mikayelyan Date: Wed, 27 Apr 2016 20:20:51 -0700 Subject: [PATCH 53/57] usb: dwc2: host: Setting qtd to NULL after freeing it This is safety change added while doing slub debugging. Affected functions: dwc2_hcd_qtd_unlink_and_free() _dwc2_hcd_urb_enqueue() Signed-off-by: Vardan Mikayelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd.c | 1 + drivers/usb/dwc2/hcd.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 1f6255131857..2df3d04d26f5 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4703,6 +4703,7 @@ fail2: spin_unlock_irqrestore(&hsotg->lock, flags); urb->hcpriv = NULL; kfree(qtd); + qtd = NULL; fail1: if (qh_allocated) { struct dwc2_qtd *qtd2, *qtd2_tmp; diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 89fa26cb25f4..7758bfb644ff 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -552,6 +552,7 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, { list_del(&qtd->qtd_list_entry); kfree(qtd); + qtd = NULL; } /* Descriptor DMA support functions */ From 907a444718b8f93956acac1c944d880c54ab900d Mon Sep 17 00:00:00 2001 From: Sevak Arakelyan Date: Wed, 27 Apr 2016 20:20:53 -0700 Subject: [PATCH 54/57] usb: dwc2: Fixed SOF interrupt enabling/disabling In case of DDMA mode we don't need to get an SOF interrupt so disable the unmasking of SOF interrupt in DDMA mode. Signed-off-by: Sevak Arakelyan Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/hcd_queue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 7f634fd771c7..b5c7793a2df2 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -1709,7 +1709,8 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) dwc2_deschedule_periodic(hsotg, qh); hsotg->periodic_qh_count--; - if (!hsotg->periodic_qh_count) { + if (!hsotg->periodic_qh_count && + hsotg->core_params->dma_desc_enable <= 0) { intr_mask = dwc2_readl(hsotg->regs + GINTMSK); intr_mask &= ~GINTSTS_SOF; dwc2_writel(intr_mask, hsotg->regs + GINTMSK); From a6ef3e02542a33fb705e6977221deb0292b27398 Mon Sep 17 00:00:00 2001 From: John Youn Date: Wed, 27 Apr 2016 20:20:56 -0700 Subject: [PATCH 55/57] usb: dwc2: Proper cleanup on dr_mode failure Cleanup in probe if we fail to get dr_mode. Signed-off-by: John Youn Signed-off-by: Felipe Balbi --- drivers/usb/dwc2/platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 88629bed6614..fc6f5251de5d 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -562,7 +562,7 @@ static int dwc2_driver_probe(struct platform_device *dev) retval = dwc2_get_dr_mode(hsotg); if (retval) - return retval; + goto error; /* * Reset before dwc2_get_hwparams() then it could get power-on real From 676e3497448177bdb1934cbc4402f921730a5864 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 26 Apr 2016 10:49:07 +0300 Subject: [PATCH 56/57] usb: dwc3: gadget: update DCFG.NumP to max burst size NumP field of DCFG register is used on NumP field of ACK TP header and it tells the host how many packets an endpoint can receive before waiting for synchronization. Documentation says it should be set to anything <=bMaxBurst. Interestingly, however, this setting is not per-endpoint how it should be (different endpoints could have different burst sizes), but things seem to work okay right now. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/gadget.c | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 87df6dd20d23..c5f576aa1903 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -271,6 +271,9 @@ #define DWC3_DCFG_LOWSPEED (2 << 0) #define DWC3_DCFG_FULLSPEED1 (3 << 0) +#define DWC3_DCFG_NUMP_SHIFT 17 +#define DWC3_DCFG_NUMP(n) (((n) & 0x1f) >> DWC3_DCFG_NUMP_SHIFT) +#define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT) #define DWC3_DCFG_LPM_CAP (1 << 22) /* Device Control Register */ diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 43efb627d1cf..4b681b0d420f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -464,9 +464,19 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep, /* Burst size is only needed in SuperSpeed mode */ if (dwc->gadget.speed >= USB_SPEED_SUPER) { - u32 burst = dep->endpoint.maxburst - 1; + u32 burst = dep->endpoint.maxburst; + u32 nump; + u32 reg; - params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst); + /* update NumP */ + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + nump = DWC3_DCFG_NUMP(reg); + nump = max(nump, burst); + reg &= ~DWC3_DCFG_NUMP_MASK; + reg |= nump << DWC3_DCFG_NUMP_SHIFT; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); + + params.param0 |= DWC3_DEPCFG_BURST_SIZE(burst - 1); } if (ignore) From 2a58f9c12bb360f38fb39e470bb5ff94014356e6 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Thu, 28 Apr 2016 10:56:28 +0300 Subject: [PATCH 57/57] usb: dwc3: gadget: disable automatic calculation of ACK TP NUMP Now that we calculate DCFG.NUMP, we can disable dwc3's automatic calculation so we maximize our chances of very high throughtput through the use of bursts. Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.h | 5 +++++ drivers/usb/dwc3/gadget.c | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index c5f576aa1903..186a8868829f 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -165,6 +165,11 @@ #define DWC3_DESCFETCHQ 13 #define DWC3_EVENTQ 15 +/* Global RX Threshold Configuration Register */ +#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19) +#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24) +#define DWC3_GRXTHRCFG_PKTCNTSEL (1 << 29) + /* Global Configuration Register */ #define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19) #define DWC3_GCTL_U2RSTECN (1 << 16) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 4b681b0d420f..c3b0d01e1960 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1669,6 +1669,17 @@ static int dwc3_gadget_start(struct usb_gadget *g, } dwc3_writel(dwc->regs, DWC3_DCFG, reg); + /* + * We are telling dwc3 that we want to use DCFG.NUMP as ACK TP's NUMP + * field instead of letting dwc3 itself calculate that automatically. + * + * This way, we maximize the chances that we'll be able to get several + * bursts of data without going through any sort of endpoint throttling. + */ + reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); + reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL; + dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); + /* Start with SuperSpeed Default */ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);