Merge "dwc3: resize txfifo of IN/INT endpoint before enabling it"
This commit is contained in:
commit
5feaf32da4
4 changed files with 93 additions and 94 deletions
|
@ -543,6 +543,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;
|
||||
|
@ -583,6 +584,7 @@ struct dwc3_ep {
|
|||
struct dwc3_ep_events dbg_ep_events;
|
||||
struct dwc3_ep_events dbg_ep_events_diff;
|
||||
struct timespec dbg_ep_events_ts;
|
||||
int fifo_depth;
|
||||
};
|
||||
|
||||
enum dwc3_phy {
|
||||
|
@ -813,7 +815,6 @@ struct dwc3_scratchpad_array {
|
|||
* @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
|
||||
|
@ -853,6 +854,7 @@ struct dwc3_scratchpad_array {
|
|||
* @imod_interval: set the interrupt moderation interval in 250ns
|
||||
* increments or 0 to disable.
|
||||
* @create_reg_debugfs: create debugfs entry to allow dwc3 register dump
|
||||
* @last_fifo_depth: total TXFIFO depth of all enabled USB IN/INT endpoints
|
||||
*/
|
||||
struct dwc3 {
|
||||
struct usb_ctrlrequest *ctrl_req;
|
||||
|
@ -988,7 +990,6 @@ struct dwc3 {
|
|||
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;
|
||||
|
@ -1050,6 +1051,7 @@ struct dwc3 {
|
|||
|
||||
wait_queue_head_t wait_linkstate;
|
||||
bool create_reg_debugfs;
|
||||
int last_fifo_depth;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
@ -1199,7 +1201,7 @@ 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);
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep);
|
||||
|
||||
/* check whether we are on the DWC_usb3 core */
|
||||
static inline bool dwc3_is_usb3(struct dwc3 *dwc)
|
||||
|
|
|
@ -1132,7 +1132,8 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request)
|
|||
struct dwc3_gadget_ep_cmd_params params;
|
||||
const struct usb_endpoint_descriptor *desc = ep->desc;
|
||||
const struct usb_ss_ep_comp_descriptor *comp_desc = ep->comp_desc;
|
||||
u32 reg;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
memset(¶ms, 0x00, sizeof(params));
|
||||
|
||||
|
@ -1181,6 +1182,10 @@ static void gsi_configure_ep(struct usb_ep *ep, struct usb_gsi_request *request)
|
|||
|
||||
/* Set XferRsc Index for GSI EP */
|
||||
if (!(dep->flags & DWC3_EP_ENABLED)) {
|
||||
ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
memset(¶ms, 0x00, sizeof(params));
|
||||
params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
|
||||
dwc3_send_gadget_ep_cmd(dwc, dep->number,
|
||||
|
|
|
@ -601,8 +601,9 @@ 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;
|
||||
|
||||
cfg = le16_to_cpu(ctrl->wValue);
|
||||
|
||||
|
@ -611,6 +612,24 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
return -EINVAL;
|
||||
|
||||
case USB_STATE_ADDRESS:
|
||||
/* Read ep0IN related TXFIFO size */
|
||||
dwc->last_fifo_depth = (dwc3_readl(dwc->regs,
|
||||
DWC3_GTXFIFOSIZ(0)) & 0xFFFF);
|
||||
/* Clear existing allocated TXFIFO for all IN eps except ep0 */
|
||||
for (num = 0; num < dwc->num_in_eps; num++) {
|
||||
dep = dwc->eps[(num << 1) | 1];
|
||||
if (num) {
|
||||
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), 0);
|
||||
dep->fifo_depth = 0;
|
||||
} else {
|
||||
dep->fifo_depth = dwc->last_fifo_depth;
|
||||
}
|
||||
|
||||
dev_dbg(dwc->dev, "%s(): %s dep->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))) {
|
||||
|
@ -635,9 +654,6 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||
DWC3_DCTL_ACCEPTU2ENA);
|
||||
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||||
}
|
||||
|
||||
dwc->resize_fifos = true;
|
||||
dwc3_trace(trace_dwc3_ep0, "resize FIFOs flag SET");
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1085,11 +1101,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)
|
||||
{
|
||||
int ret;
|
||||
if (dwc->resize_fifos) {
|
||||
dwc3_trace(trace_dwc3_ep0, "Resizing FIFOs");
|
||||
dwc3_gadget_resize_tx_fifos(dwc);
|
||||
dwc->resize_fifos = 0;
|
||||
}
|
||||
|
||||
ret = dwc3_ep0_start_control_status(dep);
|
||||
if (WARN_ON_ONCE(ret))
|
||||
|
|
|
@ -172,88 +172,64 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
|
|||
*
|
||||
* Unfortunately, due to many variables that's not always the case.
|
||||
*/
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
|
||||
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
int last_fifo_depth = 0;
|
||||
int ram1_depth;
|
||||
int fifo_size;
|
||||
int mdwidth;
|
||||
int num;
|
||||
int num_eps;
|
||||
int max_packet = 1024;
|
||||
struct usb_composite_dev *cdev = get_gadget_data(&dwc->gadget);
|
||||
int fifo_size, mdwidth, max_packet = 1024;
|
||||
int tmp, mult = 1;
|
||||
|
||||
if (!(cdev && cdev->config) || !dwc->needs_fifo_resize)
|
||||
if (!dwc->needs_fifo_resize)
|
||||
return 0;
|
||||
|
||||
num_eps = dwc->num_in_eps;
|
||||
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;
|
||||
last_fifo_depth = (dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0)) & 0xFFFF);
|
||||
dev_dbg(dwc->dev, "%s: num eps:%d max_packet:%d last_fifo_depth:%04x\n",
|
||||
__func__, num_eps, max_packet, last_fifo_depth);
|
||||
|
||||
/* Don't resize ep0IN TxFIFO, start with ep1IN only. */
|
||||
for (num = 1; num < num_eps; num++) {
|
||||
/* bit0 indicates direction; 1 means IN ep */
|
||||
struct dwc3_ep *dep = dwc->eps[(num << 1) | 1];
|
||||
int mult = 1;
|
||||
int tmp;
|
||||
|
||||
tmp = max_packet + mdwidth;
|
||||
/*
|
||||
* Interfaces like MBIM or ECM is having multiple data
|
||||
* interfaces. SET_CONFIG() happens before set_alt with
|
||||
* data interface 1 which results into calling this API
|
||||
* before GSI endpoint enabled. This results no txfifo
|
||||
* resize with GSI endpoint causing low throughput. Hence
|
||||
* use mult as 3 for GSI IN endpoint always irrespective
|
||||
* USB speed.
|
||||
*/
|
||||
if (dep->endpoint.ep_type == EP_TYPE_GSI ||
|
||||
dep->endpoint.endless)
|
||||
mult = 3;
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED)) {
|
||||
dev_dbg(dwc->dev, "ep%dIn not enabled", num);
|
||||
goto resize_fifo;
|
||||
}
|
||||
|
||||
if (((dep->endpoint.maxburst > 1) &&
|
||||
usb_endpoint_xfer_bulk(dep->endpoint.desc))
|
||||
|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
mult = 3;
|
||||
|
||||
resize_fifo:
|
||||
tmp *= mult;
|
||||
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);
|
||||
|
||||
last_fifo_depth += (fifo_size & 0xffff);
|
||||
if (dwc->tx_fifo_size &&
|
||||
(last_fifo_depth >= dwc->tx_fifo_size)) {
|
||||
/*
|
||||
* Fifo size allocated exceeded available RAM size.
|
||||
* Hence return error.
|
||||
*/
|
||||
dev_err(dwc->dev, "Fifosize(%d) > available RAM(%d)\n",
|
||||
last_fifo_depth, dwc->tx_fifo_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
|
||||
/* resize IN endpoints excepts ep0 */
|
||||
if (!usb_endpoint_dir_in(dep->endpoint.desc) ||
|
||||
dep->endpoint.ep_num == 0)
|
||||
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.ep_type == EP_TYPE_GSI || dep->endpoint.endless)
|
||||
mult = 3;
|
||||
|
||||
if (((dep->endpoint.maxburst > 1) &&
|
||||
usb_endpoint_xfer_bulk(dep->endpoint.desc))
|
||||
|| usb_endpoint_xfer_isoc(dep->endpoint.desc))
|
||||
mult = 3;
|
||||
|
||||
tmp = ((max_packet + mdwidth) * mult) + mdwidth;
|
||||
fifo_size = DIV_ROUND_UP(tmp, mdwidth);
|
||||
dep->fifo_depth = fifo_size;
|
||||
fifo_size |= (dwc->last_fifo_depth << 16);
|
||||
dwc->last_fifo_depth += (fifo_size & 0xffff);
|
||||
|
||||
dev_dbg(dwc->dev, "%s ep_num:%d last_fifo_depth:%04x fifo_depth:%d\n",
|
||||
dep->endpoint.name, dep->endpoint.ep_num, 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->tx_fifo_size &&
|
||||
((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);
|
||||
dwc->last_fifo_depth -= (fifo_size & 0xffff);
|
||||
dep->fifo_depth = 0;
|
||||
WARN_ON(1);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->endpoint.ep_num),
|
||||
fifo_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -622,6 +598,17 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
|||
dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED)) {
|
||||
dep->endpoint.desc = desc;
|
||||
dep->comp_desc = comp_desc;
|
||||
dep->type = usb_endpoint_type(desc);
|
||||
ret = dwc3_gadget_resize_tx_fifos(dwc, dep);
|
||||
if (ret) {
|
||||
dep->endpoint.desc = NULL;
|
||||
dep->comp_desc = NULL;
|
||||
dep->type = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dwc3_gadget_start_config(dwc, dep);
|
||||
if (ret) {
|
||||
dev_err(dwc->dev, "start_config() failed for %s\n",
|
||||
|
@ -641,9 +628,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
|||
struct dwc3_trb *trb_st_hw;
|
||||
struct dwc3_trb *trb_link;
|
||||
|
||||
dep->endpoint.desc = desc;
|
||||
dep->comp_desc = comp_desc;
|
||||
dep->type = usb_endpoint_type(desc);
|
||||
dep->flags |= DWC3_EP_ENABLED;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
|
||||
|
@ -2894,9 +2878,6 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
|
|||
dwc3_stop_active_transfers(dwc);
|
||||
dwc3_clear_stall_all_ep(dwc);
|
||||
|
||||
/* bus reset issued due to missing status stage of a control transfer */
|
||||
dwc->resize_fifos = 0;
|
||||
|
||||
/* Reset device address to zero */
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
|
||||
reg &= ~(DWC3_DCFG_DEVADDR_MASK);
|
||||
|
|
Loading…
Add table
Reference in a new issue