Merge "dwc3: resize txfifo of IN/INT endpoint before enabling it"

This commit is contained in:
Linux Build Service Account 2018-10-03 19:21:05 -07:00 committed by Gerrit - the friendly Code Review server
commit 5feaf32da4
4 changed files with 93 additions and 94 deletions

View file

@ -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)

View file

@ -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(&params, 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(&params, 0x00, sizeof(params));
params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
dwc3_send_gadget_ep_cmd(dwc, dep->number,

View file

@ -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))

View file

@ -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);