Skip to content

Commit

Permalink
usb: dwc3: gadget: Correct handling of scattergather lists
Browse files Browse the repository at this point in the history
The code logic in dwc3_prepare_one_trb() incorrectly uses the address
and length fields present in req packet for mapping TRB's instead of
using the address and length fields of scattergather lists. This patch
correct's the code to use sg->address and sg->length when scattergather
lists are present.

Signed-off-by: Anurag Kumar Vulisha <anuragku@xilinx.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
  • Loading branch information
Anurag Kumar Vulisha authored and Felipe Balbi committed May 21, 2018
1 parent 5f0b74e commit a31e63b
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 3 deletions.
2 changes: 2 additions & 0 deletions drivers/usb/dwc3/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,7 @@ struct dwc3_hwparams {
* @list: a list_head used for request queueing
* @dep: struct dwc3_ep owning this request
* @sg: pointer to first incomplete sg
* @start_sg: pointer to the sg which should be queued next
* @num_pending_sgs: counter to pending sgs
* @remaining: amount of data remaining
* @epnum: endpoint number to which this request refers
Expand All @@ -848,6 +849,7 @@ struct dwc3_request {
struct list_head list;
struct dwc3_ep *dep;
struct scatterlist *sg;
struct scatterlist *start_sg;

unsigned num_pending_sgs;
unsigned remaining;
Expand Down
25 changes: 22 additions & 3 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -985,11 +985,19 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
struct dwc3_request *req, unsigned chain, unsigned node)
{
struct dwc3_trb *trb;
unsigned length = req->request.length;
unsigned int length;
dma_addr_t dma;
unsigned stream_id = req->request.stream_id;
unsigned short_not_ok = req->request.short_not_ok;
unsigned no_interrupt = req->request.no_interrupt;
dma_addr_t dma = req->request.dma;

if (req->request.num_sgs > 0) {
length = sg_dma_len(req->start_sg);
dma = sg_dma_address(req->start_sg);
} else {
length = req->request.length;
dma = req->request.dma;
}

trb = &dep->trb_pool[dep->trb_enqueue];

Expand Down Expand Up @@ -1055,7 +1063,7 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
struct dwc3_request *req)
{
struct scatterlist *sg = req->sg;
struct scatterlist *sg = req->start_sg;
struct scatterlist *s;
int i;

Expand Down Expand Up @@ -1088,6 +1096,16 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
dwc3_prepare_one_trb(dep, req, chain, i);
}

/*
* There can be a situation where all sgs in sglist are not
* queued because of insufficient trb number. To handle this
* case, update start_sg to next sg to be queued, so that
* we have free trbs we can continue queuing from where we
* previously stopped
*/
if (chain)
req->start_sg = sg_next(s);

if (!dwc3_calc_trbs_left(dep))
break;
}
Expand Down Expand Up @@ -1178,6 +1196,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
return;

req->sg = req->request.sg;
req->start_sg = req->sg;
req->num_pending_sgs = req->request.num_mapped_sgs;

if (req->num_pending_sgs > 0)
Expand Down

0 comments on commit a31e63b

Please sign in to comment.