Skip to content

Commit

Permalink
usb: dwc2/gadget: assign TX FIFO dynamically
Browse files Browse the repository at this point in the history
Because we have not enough memory to have each TX FIFO of size at least
3072 bytes (the maximum single packet size with 3 transactions per
microframe), we create four FIFOs of lenght 1024, and four of length
3072 bytes, and assing them to endpoints dynamically according to
maxpacket size value of given endpoint.

Up to now there were initialized 16 TX FIFOs, but we use only 8 IN
endpoints, so we can split available memory for 8 FIFOs to have more
memory for each one.

It needed to do some small modifications in few places in code, because
there was assumption that TX FIFO numbers assigned to endpoints are the
same as the endpoint numbers, which is not true since we have dynamic
FIFO assigning.

Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Robert Baldyga authored and Greg Kroah-Hartman committed Sep 19, 2014
1 parent cff9eb7 commit b203d0a
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 30 deletions.
2 changes: 2 additions & 0 deletions drivers/usb/dwc2/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ struct s3c_hsotg_ep {
unsigned int last_load;
unsigned int fifo_load;
unsigned short fifo_size;
unsigned short fifo_index;

unsigned char dir_in;
unsigned char index;
Expand Down Expand Up @@ -197,6 +198,7 @@ struct s3c_hsotg {
int fifo_mem;
unsigned int dedicated_fifos:1;
unsigned char num_of_eps;
u32 fifo_map;

struct dentry *debug_root;
struct dentry *debug_file;
Expand Down
80 changes: 50 additions & 30 deletions drivers/usb/dwc2/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,14 +182,29 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)

/* start at the end of the GNPTXFSIZ, rounded up */
addr = 2048 + 1024;
size = 768;

/*
* currently we allocate TX FIFOs for all possible endpoints,
* and assume that they are all the same size.
* Because we have not enough memory to have each TX FIFO of size at
* least 3072 bytes (the maximum single packet size), we create four
* FIFOs of lenght 1024, and four of length 3072 bytes, and assing
* them to endpoints dynamically according to maxpacket size value of
* given endpoint.
*/

for (ep = 1; ep <= 15; ep++) {
/* 256*4=1024 bytes FIFO length */
size = 256;
for (ep = 1; ep <= 4; ep++) {
val = addr;
val |= size << FIFOSIZE_DEPTH_SHIFT;
WARN_ONCE(addr + size > hsotg->fifo_mem,
"insufficient fifo memory");
addr += size;

writel(val, hsotg->regs + DPTXFSIZN(ep));
}
/* 768*4=3072 bytes FIFO length */
size = 768;
for (ep = 5; ep <= 8; ep++) {
val = addr;
val |= size << FIFOSIZE_DEPTH_SHIFT;
WARN_ONCE(addr + size > hsotg->fifo_mem,
Expand Down Expand Up @@ -1834,7 +1849,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
if (dir_in) {
int epctl = readl(hsotg->regs + epctl_reg);

s3c_hsotg_txfifo_flush(hsotg, idx);
s3c_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);

if ((epctl & DXEPCTL_STALL) &&
(epctl & DXEPCTL_EPTYPE_BULK)) {
Expand Down Expand Up @@ -1983,6 +1998,7 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
int result, bool force)
{
struct s3c_hsotg_req *req, *treq;
unsigned size;

list_for_each_entry_safe(req, treq, &ep->queue, queue) {
/*
Expand All @@ -1996,9 +2012,11 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,
s3c_hsotg_complete_request(hsotg, ep, req,
result);
}
if (hsotg->dedicated_fifos)
if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072)
s3c_hsotg_txfifo_flush(hsotg, ep->index);
if (!hsotg->dedicated_fifos)
return;
size = (readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4;
if (size < ep->fifo_size)
s3c_hsotg_txfifo_flush(hsotg, ep->fifo_index);
}

/**
Expand Down Expand Up @@ -2439,6 +2457,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
u32 epctrl;
u32 mps;
int dir_in;
int i, val, size;
int ret = 0;

dev_dbg(hsotg->dev,
Expand Down Expand Up @@ -2511,17 +2530,8 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
break;

case USB_ENDPOINT_XFER_INT:
if (dir_in) {
/*
* Allocate our TxFNum by simply using the index
* of the endpoint for the moment. We could do
* something better if the host indicates how
* many FIFOs we are expecting to use.
*/

if (dir_in)
hs_ep->periodic = 1;
epctrl |= DXEPCTL_TXFNUM(index);
}

epctrl |= DXEPCTL_EPTYPE_INTERRUPT;
break;
Expand All @@ -2535,8 +2545,25 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
* if the hardware has dedicated fifos, we must give each IN EP
* a unique tx-fifo even if it is non-periodic.
*/
if (dir_in && hsotg->dedicated_fifos)
epctrl |= DXEPCTL_TXFNUM(index);
if (dir_in && hsotg->dedicated_fifos) {
size = hs_ep->ep.maxpacket*hs_ep->mc;
for (i = 1; i <= 8; ++i) {
if (hsotg->fifo_map & (1<<i))
continue;
val = readl(hsotg->regs + DPTXFSIZN(i));
val = (val >> FIFOSIZE_DEPTH_SHIFT)*4;
if (val < size)
continue;
hsotg->fifo_map |= 1<<i;

epctrl |= DXEPCTL_TXFNUM(i);
hs_ep->fifo_index = i;
hs_ep->fifo_size = val;
break;
}
if (i == 8)
return -ENOMEM;
}

/* for non control endpoints, set PID to D0 */
if (index)
Expand Down Expand Up @@ -2583,6 +2610,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)
/* terminate all requests with shutdown */
kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false);

hsotg->fifo_map &= ~(1<<hs_ep->fifo_index);
hs_ep->fifo_index = 0;
hs_ep->fifo_size = 0;

ctrl = readl(hsotg->regs + epctrl_reg);
ctrl &= ~DXEPCTL_EPENA;
Expand Down Expand Up @@ -2974,7 +3004,6 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
int epnum)
{
u32 ptxfifo;
char *dir;

if (epnum == 0)
Expand Down Expand Up @@ -3002,15 +3031,6 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,
usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT);
hs_ep->ep.ops = &s3c_hsotg_ep_ops;

/*
* Read the FIFO size for the Periodic TX FIFO, even if we're
* an OUT endpoint, we may as well do this if in future the
* code is changed to make each endpoint's direction changeable.
*/

ptxfifo = readl(hsotg->regs + DPTXFSIZN(epnum));
hs_ep->fifo_size = FIFOSIZE_DEPTH_GET(ptxfifo) * 4;

/*
* if we're using dma, we need to set the next-endpoint pointer
* to be something valid.
Expand Down

0 comments on commit b203d0a

Please sign in to comment.