* @sg: pointer to first incomplete sg
* @start_sg: pointer to the sg which should be queued next
* @num_pending_sgs: counter to pending sgs
+ * @num_queued_sgs: counter to the number of sgs which already got queued
* @remaining: amount of data remaining
* @epnum: endpoint number to which this request refers
* @trb: pointer to struct dwc3_trb
struct scatterlist *start_sg;
unsigned num_pending_sgs;
+ unsigned int num_queued_sgs;
unsigned remaining;
u8 epnum;
struct dwc3_trb *trb;
struct scatterlist *s;
int i;
- for_each_sg(sg, s, req->num_pending_sgs, i) {
+ unsigned int remaining = req->request.num_mapped_sgs
+ - req->num_queued_sgs;
+
+ for_each_sg(sg, s, remaining, i) {
unsigned int length = req->request.length;
unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc);
unsigned int rem = length % maxp;
if (chain)
req->start_sg = sg_next(s);
+ req->num_queued_sgs++;
+
if (!dwc3_calc_trbs_left(dep))
break;
}
req->sg = req->request.sg;
req->start_sg = req->sg;
+ req->num_queued_sgs = 0;
req->num_pending_sgs = req->request.num_mapped_sgs;
if (req->num_pending_sgs > 0)
req->request.actual = length - req->remaining;
- if ((req->request.actual < length) && req->num_pending_sgs)
- return __dwc3_gadget_kick_transfer(dep);
+ if (req->request.actual < length || req->num_pending_sgs) {
+ /*
+ * There could be a scenario where the whole req can't
+ * be mapped into available TRB's. In that case, we need
+ * to kick transfer again if (req->num_pending_sgs > 0)
+ */
+ if (req->num_pending_sgs) {
+ dev_WARN_ONCE(dwc->dev,
+ (req->request.actual == length),
+ "There are some pending sg's that needs to be queued again\n");
+ return __dwc3_gadget_kick_transfer(dep);
+ }
+ }
dwc3_gadget_giveback(dep, req, status);