Skip to content

Commit a31e63b

Browse files
Anurag Kumar VulishaFelipe Balbi
authored andcommitted
usb: dwc3: gadget: Correct handling of scattergather lists
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>
1 parent 5f0b74e commit a31e63b

File tree

2 files changed

+24
-3
lines changed

2 files changed

+24
-3
lines changed

drivers/usb/dwc3/core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,6 +832,7 @@ struct dwc3_hwparams {
832832
* @list: a list_head used for request queueing
833833
* @dep: struct dwc3_ep owning this request
834834
* @sg: pointer to first incomplete sg
835+
* @start_sg: pointer to the sg which should be queued next
835836
* @num_pending_sgs: counter to pending sgs
836837
* @remaining: amount of data remaining
837838
* @epnum: endpoint number to which this request refers
@@ -848,6 +849,7 @@ struct dwc3_request {
848849
struct list_head list;
849850
struct dwc3_ep *dep;
850851
struct scatterlist *sg;
852+
struct scatterlist *start_sg;
851853

852854
unsigned num_pending_sgs;
853855
unsigned remaining;

drivers/usb/dwc3/gadget.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -985,11 +985,19 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
985985
struct dwc3_request *req, unsigned chain, unsigned node)
986986
{
987987
struct dwc3_trb *trb;
988-
unsigned length = req->request.length;
988+
unsigned int length;
989+
dma_addr_t dma;
989990
unsigned stream_id = req->request.stream_id;
990991
unsigned short_not_ok = req->request.short_not_ok;
991992
unsigned no_interrupt = req->request.no_interrupt;
992-
dma_addr_t dma = req->request.dma;
993+
994+
if (req->request.num_sgs > 0) {
995+
length = sg_dma_len(req->start_sg);
996+
dma = sg_dma_address(req->start_sg);
997+
} else {
998+
length = req->request.length;
999+
dma = req->request.dma;
1000+
}
9931001

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

@@ -1055,7 +1063,7 @@ static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep)
10551063
static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
10561064
struct dwc3_request *req)
10571065
{
1058-
struct scatterlist *sg = req->sg;
1066+
struct scatterlist *sg = req->start_sg;
10591067
struct scatterlist *s;
10601068
int i;
10611069

@@ -1088,6 +1096,16 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
10881096
dwc3_prepare_one_trb(dep, req, chain, i);
10891097
}
10901098

1099+
/*
1100+
* There can be a situation where all sgs in sglist are not
1101+
* queued because of insufficient trb number. To handle this
1102+
* case, update start_sg to next sg to be queued, so that
1103+
* we have free trbs we can continue queuing from where we
1104+
* previously stopped
1105+
*/
1106+
if (chain)
1107+
req->start_sg = sg_next(s);
1108+
10911109
if (!dwc3_calc_trbs_left(dep))
10921110
break;
10931111
}
@@ -1178,6 +1196,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
11781196
return;
11791197

11801198
req->sg = req->request.sg;
1199+
req->start_sg = req->sg;
11811200
req->num_pending_sgs = req->request.num_mapped_sgs;
11821201

11831202
if (req->num_pending_sgs > 0)

0 commit comments

Comments
 (0)