RE: [PATCH] usb: dwc3: gadget: Correct the logic for queuing sgs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Felipe,

Thanks for reviewing the patch , please find my comments inline

>-----Original Message-----
>From: Felipe Balbi [mailto:balbi@xxxxxxxxxx]
>Sent: Monday, March 19, 2018 2:21 PM
>To: Anurag Kumar Vulisha <anuragku@xxxxxxxxxx>; Greg Kroah-Hartman
><gregkh@xxxxxxxxxxxxxxxxxxx>
>Cc: v.anuragkumar@xxxxxxxxx; Ajay Yugalkishore Pandey
><APANDEY@xxxxxxxxxx>; linux-usb@xxxxxxxxxxxxxxx; linux-
>kernel@xxxxxxxxxxxxxxx; Anurag Kumar Vulisha <anuragku@xxxxxxxxxx>
>Subject: Re: [PATCH] usb: dwc3: gadget: Correct the logic for queuing sgs
>
>
>Hi,
>
>Anurag Kumar Vulisha <anurag.kumar.vulisha@xxxxxxxxxx> writes:
>> This patch fixes two issues
>>
>> 1. The code logic in dwc3_prepare_one_trb() incorrectly uses the
>> address and length given in req packet even for scattergather lists.
>> This patch correct's the code to use sg->address and sg->length when
>> scattergather lists are present.
>>
>> 2. The present code correctly fetches the req's which were not queued
>> from the started_list but fails to start from the sg where it
>> previously stopped queuing because of the unavailable TRB's. This
>> patch correct's the code to start queuing from the correct sg in sglist.
>
>these two should be in separate patches, then.
>
Will create separate patches in next version

>> Signed-off-by: Anurag Kumar Vulisha <anuragku@xxxxxxxxxx>
>> ---
>>  drivers/usb/dwc3/core.h   |  4 ++++
>>  drivers/usb/dwc3/gadget.c | 42
>> ++++++++++++++++++++++++++++++++++++------
>>  2 files changed, 40 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index
>> 860d2bc..2779e58 100644
>> --- a/drivers/usb/dwc3/core.h
>> +++ b/drivers/usb/dwc3/core.h
>> @@ -718,7 +718,9 @@ struct dwc3_hwparams {
>>   * @list: a list_head used for request queueing
>>   * @dep: struct dwc3_ep owning this request
>>   * @sg: pointer to first incomplete sg
>> + * @sg_to_start: 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
>
>this is the same as num_pending_sgs.

num_pending_sgs is initially pointing to num_mapped_sgs, which gets decremented in dwc3_cleanup_done_reqs(). Consider a case where the driver failed to queue all sgs into TRBs because of insufficient TRB number. For example, lets assume req has 5 sgs and only 3 got queued. In this scenario ,when the dwc3_cleanup_done_reqs() gets called the value of  num_pending_sgs = 5. Since the value of num_pending_sgs is greater than 0, __dwc3_gadget_kick_transfer() gets called with num_pending_sgs = 5-1 = 4 . Eventually __dwc3_gadget_kick_transfer()  calls dwc3_prepare_one_trb_sg() which has for_each_sg() call which loops for num_pending_sgs times (4 times in our example). This is incorrect, ideally it should be called only for 2 times because we have only 2 sgs which previously were not queued . So, we added an extra flag num_queued_sgs which counts the number of sgs that got queued successfully and make  for_each_sg() loop for num_mapped_sgs - num_queued_sgs times only . In our example case with the updated logic, it will loop for 5 - 3 = 2 times only. Because of this reason added num_queued_sgs  flag. Please correct me if I am wrong.

>
>>   * @remaining: amount of data remaining
>>   * @epnum: endpoint number to which this request refers
>>   * @trb: pointer to struct dwc3_trb
>> @@ -734,8 +736,10 @@ struct dwc3_request {
>>         struct list_head        list;
>>         struct dwc3_ep          *dep;
>>         struct scatterlist      *sg;
>> +       struct scatterlist      *sg_to_start;
>
>indeed, we seem to need something like this.
>
>>         unsigned                num_pending_sgs;
>> +       unsigned int            num_queued_sgs;
>
>this should be unnecessary.

The explanation given above is valid for this comment also. Please refer the explanation given above

>
>> diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
>> index 2bda4eb..1cffed5 100644
>> --- a/drivers/usb/dwc3/gadget.c
>> +++ b/drivers/usb/dwc3/gadget.c
>> @@ -978,11 +978,20 @@ 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) {
>> +               /* Use scattergather list address and length */
>
>unnecessary comment

Will remove the comment

>
>> +               length = sg_dma_len(req->sg_to_start);
>> +               dma = sg_dma_address(req->sg_to_start);
>> +       } else {
>> +               length = req->request.length;
>> +               dma = req->request.dma;
>> +       }
>>
>>         trb = &dep->trb_pool[dep->trb_enqueue];
>>
>> @@ -1048,11 +1057,14 @@ 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->sg_to_start;
>>         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;
>
>already tracked as num_pending_sgs

The explanation given above is valid for this comment also. Please refer the above mentioned explanation. 
>
>> +       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; @@ -1081,6 +1093,16
>> @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep,
>>                         dwc3_prepare_one_trb(dep, req, chain, i);
>>                 }
>>
>> +               /* In the case where not able to queue trbs for all
>> + sgs in
>
>wrong comment style
>

Will fix this in next version of patch

>> +                * request because of trb not available, update sg_to_start
>> +                * to next sg from which we can start queing trbs once trbs
>> +                * availbale
>                     ^^^^^^^^^
>                     available
>
>sg_to_start is too long and awkward to type. Sure, I'm nitpicking, but start_sg
>would be better.

I agree with you, start_sg looks better. Will fix this in next series of patch
 
>
>> +                */
>> +               if (chain)
>> +                       req->sg_to_start = sg_next(s);
>> +
>> +               req->num_queued_sgs++;
>> +
>>                 if (!dwc3_calc_trbs_left(dep))
>>                         break;
>>         }
>> @@ -1171,6 +1193,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
>>                         return;
>>
>>                 req->sg                 = req->request.sg;
>> +               req->sg_to_start        = req->sg;
>> +               req->num_queued_sgs     = 0;
>
>num_queued_sgs is unnecessary.

As said in previous explanation, we use num_queued_sgs to  correctly maintain the incomplete sgs. So, clearing it to 0.

>
>>                 req->num_pending_sgs    = req->request.num_mapped_sgs;
>>
>>                 if (req->num_pending_sgs > 0) @@ -2327,8 +2351,14 @@
>> static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep
>> *dep,
>>
>>                 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) {
>
>why do you think this needs to be || instead of &&? If actual == length we're
>done, there's nothing more left to do. If there is either host sent more data than
>it should, or we miscalculated num_pending_sgs, or we had the wrong length
>somewhere in some TRBs. Either of those cases is an error condition we don't
>want to hide. We want things to fail in that case.
>

Consider the same example that we had previously discussed, among the 5 sgs only 3 sgs got queued and all 3 sgs got completed successfully. The req->remaining field represents the size of TRB which was not transferred. In this example , as 3 sgs got completed successfully the req-> remaining = 0. So , request.actual = length - 0 (req->remaining)  which means request.actual == length.  Because of this , the condition check  if ((req->request.actual < length) && req->num_pending_sgs) ) fails even though we have req->num_pending_sgs > 0.  So, corrected the logic to always kick transfer for two conditions 1) if req->num_pending_sgs > 0  2) if ((req->request.actual < length) && req->num_pending_sgs)) condition satisfies. Please correct me If my understanding is wrong.

>> +                       /* There could be cases where the whole req
>> + can't be
>
>wrong comment style.
>
Will correct this in next series of patches

>> +                        * mapped into TRB's available. In that case, we need
>> +                        * to kick transfer again if (req->num_pending_sgs > 0)
>> +                        */
>
>also, the code has already been trying to do that. It just wasn't correct. We don't
>need to add this comment.

Added the comment to describe what is happening here. Please let me know if any more information needs to be added or deleted.

>
>> +                       if (req->num_pending_sgs)
>> +                               return
>> + __dwc3_gadget_kick_transfer(dep);
>
>another num_pending_sgs check? Why?

As explained in the previous comment, changed the logic to make it work for two conditions 1) if req->num_pending_sgs > 0  2) if ((req->request.actual < length) && req->num_pending_sgs)) . 

>
>> This email and any attachments are intended for the sole use of the
>> named recipient(s) and contain(s) confidential information that may be
>> proprietary, privileged or copyrighted under applicable law. If you
>> are not the intended recipient, do not read, copy, or forward this
>> email message or any attachments. Delete this email message and any
>> attachments immediately.
>
>I can't accept ANY patches from you until you remove this footer. In fact, I'm not
>in the To field, so I'm not a "named recipient" and therefore, I'm deleting your
>email. Talk to your IT department about contributing to public mailing lists.
>
Sorry for the inconvenience caused. Unknowingly , this message got added. I will ensure that this message won't appear in future emails.

Thanks,
Anurag Kumar Vulisha

>Email, now, deleted.
>
>--
>balbi
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux