Skip to content

Commit

Permalink
usb: dwc3: gadget: dynamically re-size TxFifos
Browse files Browse the repository at this point in the history
We need to dynamically re-size TxFifos for the
cases where default values will not do.

While at that, we create a simple function which,
for now, will just allocate one full packet fifo
space for each of the enabled endpoints.

This can be improved later in order to allow for
better throughput by allocating more space for
endpoints which could make good use of that like
isochronous and bulk.

Signed-off-by: Felipe Balbi <[email protected]>
  • Loading branch information
Felipe Balbi committed Feb 6, 2012
1 parent bb5cfd6 commit 457e84b
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 2 deletions.
5 changes: 5 additions & 0 deletions drivers/usb/dwc3/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>

#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
Expand Down Expand Up @@ -404,6 +405,7 @@ static void dwc3_core_exit(struct dwc3 *dwc)

static int __devinit dwc3_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct resource *res;
struct dwc3 *dwc;

Expand Down Expand Up @@ -469,6 +471,9 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
else
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;

if (of_get_property(node, "tx-fifo-resize", NULL))
dwc->needs_fifo_resize = true;

pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
pm_runtime_forbid(&pdev->dev);
Expand Down
16 changes: 15 additions & 1 deletion drivers/usb/dwc3/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)

/* Global TX Fifo Size Register */
#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)

/* Global HWPARAMS1 Register */
#define DWC3_GHWPARAMS1_EN_PWROPT(n) ((n & (3 << 24)) >> 24)
#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
Expand Down Expand Up @@ -546,8 +550,13 @@ struct dwc3_hwparams {
#define DWC3_MODE_DRD 2
#define DWC3_MODE_HUB 3

#define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8)

/* HWPARAMS1 */
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)

/* HWPARAMS7 */
#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)

struct dwc3_request {
struct usb_request request;
Expand Down Expand Up @@ -594,6 +603,8 @@ struct dwc3_request {
* @ep0_expect_in: true when we expect a DATA IN transfer
* @start_config_issued: true when StartConfig command has been issued
* @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
Expand Down Expand Up @@ -651,6 +662,8 @@ struct dwc3 {
unsigned start_config_issued:1;
unsigned setup_packet_pending:1;
unsigned delayed_status:1;
unsigned needs_fifo_resize:1;
unsigned resize_fifos:1;

enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
Expand Down Expand Up @@ -812,6 +825,7 @@ union dwc3_event {

/* prototypes */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);

int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);
Expand Down
11 changes: 10 additions & 1 deletion drivers/usb/dwc3/ep0.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
case DWC3_ADDRESS_STATE:
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)))
if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
dwc->dev_state = DWC3_CONFIGURED_STATE;
dwc->resize_fifos = true;
dev_dbg(dwc->dev, "resize fifos flag SET\n");
}
break;

case DWC3_CONFIGURED_STATE:
Expand Down Expand Up @@ -707,6 +710,12 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
{
struct dwc3_ep *dep = dwc->eps[epnum];

if (dwc->resize_fifos) {
dev_dbg(dwc->dev, "starting to resize fifos\n");
dwc3_gadget_resize_tx_fifos(dwc);
dwc->resize_fifos = 0;
}

WARN_ON(dwc3_ep0_start_control_status(dep));
}

Expand Down
74 changes: 74 additions & 0 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,80 @@ 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 < DWC3_ENDPOINTS_NUM; num++) {
struct dwc3_ep *dep = dwc->eps[num];
int fifo_number = dep->number >> 1;
int tmp;

if (!(dep->number & 1))
continue;

if (!(dep->flags & DWC3_EP_ENABLED))
continue;

tmp = dep->endpoint.maxpacket;
tmp += mdwidth;
tmp += mdwidth;

fifo_size = DIV_ROUND_UP(tmp, mdwidth);
fifo_size |= (last_fifo_depth << 16);

dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
dep->name, last_fifo_depth, fifo_size & 0xffff);

dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number),
fifo_size);

last_fifo_depth += (fifo_size & 0xffff);
}

return 0;
}

void dwc3_map_buffer_to_dma(struct dwc3_request *req)
{
struct dwc3 *dwc = req->dep->dwc;
Expand Down

0 comments on commit 457e84b

Please sign in to comment.