Loading drivers/usb/dwc3/core.c +3 −0 Original line number Diff line number Diff line Loading @@ -1347,6 +1347,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) device_property_read_u8(dev, "snps,tx-max-burst-prd", &tx_max_burst_prd); 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, Loading drivers/usb/dwc3/core.h +11 −0 Original line number Diff line number Diff line Loading @@ -726,6 +726,7 @@ struct dwc3_ep_events { * @dbg_ep_events: different events counter for endpoint * @dbg_ep_events_diff: differential events counter for endpoint * @dbg_ep_events_ts: timestamp for previous event counters * @fifo_depth: allocated TXFIFO depth */ struct dwc3_ep { struct usb_ep endpoint; Loading Loading @@ -1062,6 +1063,7 @@ struct dwc3_scratchpad_array { * 1 - utmi_l1_suspend_n * @is_fpga: true when we are using the FPGA board * @pending_events: true when we have pending IRQs to be handled * @needs_fifo_resize: not all users might want fifo resizing, flag it * @pullups_connected: true when Run/Stop bit is set * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @three_stage_setup: set if we perform a three phase setup Loading Loading @@ -1111,6 +1113,8 @@ struct dwc3_scratchpad_array { * @xhci_imod_value: imod value to use with xhci * @index: dwc3's instance number * @dwc_ipc_log_ctxt: dwc3 ipc log context * @tx_fifo_size: Available RAM size for TX fifo allocation * @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints * @irq_cnt: total irq count * @bh_completion_time: time taken for taklet completion * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt Loading Loading @@ -1275,6 +1279,7 @@ struct dwc3 { unsigned is_utmi_l1_suspend:1; unsigned is_fpga:1; unsigned pending_events:1; unsigned needs_fifo_resize:1; unsigned pullups_connected:1; unsigned setup_packet_pending:1; unsigned three_stage_setup:1; Loading Loading @@ -1322,6 +1327,8 @@ struct dwc3 { unsigned int index; void *dwc_ipc_log_ctxt; struct dwc3_gadget_events dbg_gadget_events; int tx_fifo_size; int last_fifo_depth; /* IRQ timing statistics */ int irq; Loading Loading @@ -1538,6 +1545,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param); int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep); void dwc3_gadget_disable_irq(struct dwc3 *dwc); int dwc3_core_init(struct dwc3 *dwc); int dwc3_event_buffers_setup(struct dwc3 *dwc); Loading @@ -1562,6 +1570,9 @@ static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { return 0; } static inline int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep) { return 0; } static inline void dwc3_gadget_disable_irq(struct dwc3 *dwc) { } static int dwc3_core_init(struct dwc3 *dwc) Loading drivers/usb/dwc3/ep0.c +39 −1 Original line number Diff line number Diff line Loading @@ -603,8 +603,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { enum usb_device_state state = dwc->gadget.state; u32 cfg; int ret; int ret, num; u32 reg; struct dwc3_ep *dep; int size; cfg = le16_to_cpu(ctrl->wValue); Loading @@ -613,6 +615,42 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return -EINVAL; case USB_STATE_ADDRESS: /* * If tx-fifo-resize flag is not set for the controller, then * do not clear existing allocated TXFIFO since we do not * allocate it again in dwc3_gadget_resize_tx_fifos */ if (dwc->needs_fifo_resize && dwc->tx_fifo_size) { /* Read ep0IN related TXFIFO size */ dep = dwc->eps[1]; size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); if (dwc3_is_usb31(dwc)) dep->fifo_depth = DWC31_GTXFIFOSIZ_TXFDEF(size); else dep->fifo_depth = DWC3_GTXFIFOSIZ_TXFDEF(size); dwc->last_fifo_depth = dep->fifo_depth; /* Clear existing TXFIFO for all IN eps except ep0 */ for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); num += 2) { dep = dwc->eps[num]; size = 0; /* Don't change TXFRAMNUM on usb31 version */ if (dwc3_is_usb31(dwc)) size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) & DWC31_GTXFIFOSIZ_TXFRAMNUM; dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size); dep->fifo_depth = 0; dev_dbg(dwc->dev, "%s(): %s fifo_depth:%x\n", __func__, dep->name, dep->fifo_depth); dbg_event(0xFF, "fifo_reset", dep->number); } } ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { Loading drivers/usb/dwc3/gadget.c +98 −0 Original line number Diff line number Diff line Loading @@ -172,6 +172,100 @@ static void dwc3_ep_inc_deq(struct dwc3_ep *dep) dwc3_ep_inc_trb(&dep->trb_dequeue); } /* * 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, struct dwc3_ep *dep) { int fifo_size, mdwidth, max_packet = 1024; int tmp, mult = 1, fifo_0_start; if (!dwc->needs_fifo_resize || !dwc->tx_fifo_size) return 0; /* resize IN endpoints excepts ep0 */ if (!usb_endpoint_dir_in(dep->endpoint.desc) || dep->number <= 1) return 0; /* Don't resize already resized IN endpoint */ if (dep->fifo_depth) { dev_dbg(dwc->dev, "%s fifo_depth:%d is already set\n", dep->endpoint.name, dep->fifo_depth); return 0; } mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); /* MDWIDTH is represented in bits, we need it in bytes */ mdwidth >>= 3; if (((dep->endpoint.maxburst > 1) && usb_endpoint_xfer_bulk(dep->endpoint.desc)) || usb_endpoint_xfer_isoc(dep->endpoint.desc)) mult = 3; if ((dep->endpoint.maxburst > 6) && usb_endpoint_xfer_bulk(dep->endpoint.desc) && dwc3_is_usb31(dwc)) mult = 6; tmp = ((max_packet + mdwidth) * mult) + mdwidth; fifo_size = DIV_ROUND_UP(tmp, mdwidth); dep->fifo_depth = fifo_size; /* Check if TXFIFOs start at non-zero addr */ tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp); fifo_size |= (fifo_0_start + (dwc->last_fifo_depth << 16)); if (dwc3_is_usb31(dwc)) dwc->last_fifo_depth += DWC31_GTXFIFOSIZ_TXFDEF(fifo_size); else dwc->last_fifo_depth += DWC3_GTXFIFOSIZ_TXFDEF(fifo_size); dev_dbg(dwc->dev, "%s ep_num:%d last_fifo_depth:%04x fifo_depth:%d\n", dep->endpoint.name, dep->number >> 1, dwc->last_fifo_depth, dep->fifo_depth); dbg_event(0xFF, "resize_fifo", dep->number); dbg_event(0xFF, "fifo_depth", dep->fifo_depth); /* Check fifo size allocation doesn't exceed available RAM size. */ if ((dwc->last_fifo_depth * mdwidth) >= dwc->tx_fifo_size) { dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n", (dwc->last_fifo_depth * mdwidth), dwc->tx_fifo_size, dep->endpoint.name, fifo_size); if (dwc3_is_usb31(dwc)) fifo_size = DWC31_GTXFIFOSIZ_TXFDEF(fifo_size); else fifo_size = DWC3_GTXFIFOSIZ_TXFDEF(fifo_size); dwc->last_fifo_depth -= fifo_size; dep->fifo_depth = 0; WARN_ON(1); return -ENOMEM; } dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size); return 0; } EXPORT_SYMBOL(dwc3_gadget_resize_tx_fifos); static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, struct dwc3_request *req, int status) { Loading Loading @@ -630,6 +724,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) int ret; if (!(dep->flags & DWC3_EP_ENABLED)) { ret = dwc3_gadget_resize_tx_fifos(dwc, dep); if (ret) return ret; ret = dwc3_gadget_start_config(dep); if (ret) { dev_err(dwc->dev, "start_config() failed for %s\n", Loading Loading
drivers/usb/dwc3/core.c +3 −0 Original line number Diff line number Diff line Loading @@ -1347,6 +1347,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) device_property_read_u8(dev, "snps,tx-max-burst-prd", &tx_max_burst_prd); 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, Loading
drivers/usb/dwc3/core.h +11 −0 Original line number Diff line number Diff line Loading @@ -726,6 +726,7 @@ struct dwc3_ep_events { * @dbg_ep_events: different events counter for endpoint * @dbg_ep_events_diff: differential events counter for endpoint * @dbg_ep_events_ts: timestamp for previous event counters * @fifo_depth: allocated TXFIFO depth */ struct dwc3_ep { struct usb_ep endpoint; Loading Loading @@ -1062,6 +1063,7 @@ struct dwc3_scratchpad_array { * 1 - utmi_l1_suspend_n * @is_fpga: true when we are using the FPGA board * @pending_events: true when we have pending IRQs to be handled * @needs_fifo_resize: not all users might want fifo resizing, flag it * @pullups_connected: true when Run/Stop bit is set * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @three_stage_setup: set if we perform a three phase setup Loading Loading @@ -1111,6 +1113,8 @@ struct dwc3_scratchpad_array { * @xhci_imod_value: imod value to use with xhci * @index: dwc3's instance number * @dwc_ipc_log_ctxt: dwc3 ipc log context * @tx_fifo_size: Available RAM size for TX fifo allocation * @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints * @irq_cnt: total irq count * @bh_completion_time: time taken for taklet completion * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt Loading Loading @@ -1275,6 +1279,7 @@ struct dwc3 { unsigned is_utmi_l1_suspend:1; unsigned is_fpga:1; unsigned pending_events:1; unsigned needs_fifo_resize:1; unsigned pullups_connected:1; unsigned setup_packet_pending:1; unsigned three_stage_setup:1; Loading Loading @@ -1322,6 +1327,8 @@ struct dwc3 { unsigned int index; void *dwc_ipc_log_ctxt; struct dwc3_gadget_events dbg_gadget_events; int tx_fifo_size; int last_fifo_depth; /* IRQ timing statistics */ int irq; Loading Loading @@ -1538,6 +1545,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param); int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep); void dwc3_gadget_disable_irq(struct dwc3 *dwc); int dwc3_core_init(struct dwc3 *dwc); int dwc3_event_buffers_setup(struct dwc3 *dwc); Loading @@ -1562,6 +1570,9 @@ static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd, static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) { return 0; } static inline int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep) { return 0; } static inline void dwc3_gadget_disable_irq(struct dwc3 *dwc) { } static int dwc3_core_init(struct dwc3 *dwc) Loading
drivers/usb/dwc3/ep0.c +39 −1 Original line number Diff line number Diff line Loading @@ -603,8 +603,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { enum usb_device_state state = dwc->gadget.state; u32 cfg; int ret; int ret, num; u32 reg; struct dwc3_ep *dep; int size; cfg = le16_to_cpu(ctrl->wValue); Loading @@ -613,6 +615,42 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return -EINVAL; case USB_STATE_ADDRESS: /* * If tx-fifo-resize flag is not set for the controller, then * do not clear existing allocated TXFIFO since we do not * allocate it again in dwc3_gadget_resize_tx_fifos */ if (dwc->needs_fifo_resize && dwc->tx_fifo_size) { /* Read ep0IN related TXFIFO size */ dep = dwc->eps[1]; size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); if (dwc3_is_usb31(dwc)) dep->fifo_depth = DWC31_GTXFIFOSIZ_TXFDEF(size); else dep->fifo_depth = DWC3_GTXFIFOSIZ_TXFDEF(size); dwc->last_fifo_depth = dep->fifo_depth; /* Clear existing TXFIFO for all IN eps except ep0 */ for (num = 3; num < min_t(int, dwc->num_eps, DWC3_ENDPOINTS_NUM); num += 2) { dep = dwc->eps[num]; size = 0; /* Don't change TXFRAMNUM on usb31 version */ if (dwc3_is_usb31(dwc)) size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) & DWC31_GTXFIFOSIZ_TXFRAMNUM; dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size); dep->fifo_depth = 0; dev_dbg(dwc->dev, "%s(): %s fifo_depth:%x\n", __func__, dep->name, dep->fifo_depth); dbg_event(0xFF, "fifo_reset", dep->number); } } ret = dwc3_ep0_delegate_req(dwc, ctrl); /* if the cfg matches and the cfg is non zero */ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) { Loading
drivers/usb/dwc3/gadget.c +98 −0 Original line number Diff line number Diff line Loading @@ -172,6 +172,100 @@ static void dwc3_ep_inc_deq(struct dwc3_ep *dep) dwc3_ep_inc_trb(&dep->trb_dequeue); } /* * 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, struct dwc3_ep *dep) { int fifo_size, mdwidth, max_packet = 1024; int tmp, mult = 1, fifo_0_start; if (!dwc->needs_fifo_resize || !dwc->tx_fifo_size) return 0; /* resize IN endpoints excepts ep0 */ if (!usb_endpoint_dir_in(dep->endpoint.desc) || dep->number <= 1) return 0; /* Don't resize already resized IN endpoint */ if (dep->fifo_depth) { dev_dbg(dwc->dev, "%s fifo_depth:%d is already set\n", dep->endpoint.name, dep->fifo_depth); return 0; } mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); /* MDWIDTH is represented in bits, we need it in bytes */ mdwidth >>= 3; if (((dep->endpoint.maxburst > 1) && usb_endpoint_xfer_bulk(dep->endpoint.desc)) || usb_endpoint_xfer_isoc(dep->endpoint.desc)) mult = 3; if ((dep->endpoint.maxburst > 6) && usb_endpoint_xfer_bulk(dep->endpoint.desc) && dwc3_is_usb31(dwc)) mult = 6; tmp = ((max_packet + mdwidth) * mult) + mdwidth; fifo_size = DIV_ROUND_UP(tmp, mdwidth); dep->fifo_depth = fifo_size; /* Check if TXFIFOs start at non-zero addr */ tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)); fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp); fifo_size |= (fifo_0_start + (dwc->last_fifo_depth << 16)); if (dwc3_is_usb31(dwc)) dwc->last_fifo_depth += DWC31_GTXFIFOSIZ_TXFDEF(fifo_size); else dwc->last_fifo_depth += DWC3_GTXFIFOSIZ_TXFDEF(fifo_size); dev_dbg(dwc->dev, "%s ep_num:%d last_fifo_depth:%04x fifo_depth:%d\n", dep->endpoint.name, dep->number >> 1, dwc->last_fifo_depth, dep->fifo_depth); dbg_event(0xFF, "resize_fifo", dep->number); dbg_event(0xFF, "fifo_depth", dep->fifo_depth); /* Check fifo size allocation doesn't exceed available RAM size. */ if ((dwc->last_fifo_depth * mdwidth) >= dwc->tx_fifo_size) { dev_err(dwc->dev, "Fifosize(%d) > RAM size(%d) %s depth:%d\n", (dwc->last_fifo_depth * mdwidth), dwc->tx_fifo_size, dep->endpoint.name, fifo_size); if (dwc3_is_usb31(dwc)) fifo_size = DWC31_GTXFIFOSIZ_TXFDEF(fifo_size); else fifo_size = DWC3_GTXFIFOSIZ_TXFDEF(fifo_size); dwc->last_fifo_depth -= fifo_size; dep->fifo_depth = 0; WARN_ON(1); return -ENOMEM; } dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size); return 0; } EXPORT_SYMBOL(dwc3_gadget_resize_tx_fifos); static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep, struct dwc3_request *req, int status) { Loading Loading @@ -630,6 +724,10 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action) int ret; if (!(dep->flags & DWC3_EP_ENABLED)) { ret = dwc3_gadget_resize_tx_fifos(dwc, dep); if (ret) return ret; ret = dwc3_gadget_start_config(dep); if (ret) { dev_err(dwc->dev, "start_config() failed for %s\n", Loading