summaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/gadget.c
diff options
context:
space:
mode:
authorAnurag Kumar Vulisha <anuragku@xilinx.com>2018-03-27 16:35:20 +0530
committerFelipe Balbi <felipe.balbi@linux.intel.com>2018-05-21 10:00:47 +0300
commita31e63b608ff78c77d8e033347239431d522fe5d (patch)
tree952ca738be9d8b99a03bbd91d8fff9c509400749 /drivers/usb/dwc3/gadget.c
parent5f0b74e54890c354d6ac0124ea7a96adf22845d0 (diff)
downloadop-kernel-dev-a31e63b608ff78c77d8e033347239431d522fe5d.zip
op-kernel-dev-a31e63b608ff78c77d8e033347239431d522fe5d.tar.gz
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>
Diffstat (limited to 'drivers/usb/dwc3/gadget.c')
-rw-r--r--drivers/usb/dwc3/gadget.c25
1 files changed, 22 insertions, 3 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8796a5ee..56ca166 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -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];
@@ -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;
@@ -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;
}
@@ -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)
OpenPOWER on IntegriCloud