usb: dwc3: gadget: Prevent double free scenario for cancelled_list

Suppose for a function driver the usb controller received EPCMDCMPLT
for end transfer from previous case, so as part of this the resources
for the endpoint will be released. In this process we will be clearing
the cancelled_request as part of which controller executes
gadget_giveback where the spinlock is released. Within that time if
ep_queue from the function driver is called, then the endpoint command
will fail due to no resources being present in for the endpoint, the
ep command will return -EINVAL due to no resources. This will lead
the controller to move the request to cancelled list and if the
DWC3_EP_END_TRANSFER_PENDING flag is set then it will go ahead and try
to cleanup the already cleared cancelled request.
Resulting the controller to double free the request.

This problem is only with Gen1 controllers as there the
DWC3_EP_END_TRANSFER_PENDING flag will not be set.

Fix this issue by introducing a check in ep_interrupt on EPCMDCMPLT.
If the DWC3_EP_END_TRANSFER_PENDING bit is set, then cleanup the
cancelled request. This will ensure that if it is a GEN1 controller,
cleanup cancelled request will be called from kick_transfer and if
GEN2 controller, then cleanup from ep_interrupt.

However, preventing cleaning up of cancelled list from EPCMDCMPLT has
one side effect as if from function driver ep_dequeue is called and
it does not giveback the request from there and rely on EPCMDCMPLT
to cleanup the cancelled list. Therefore the request will be moved
to cancelled list but won't be given back to function driver.

To fix this additionally have introduced the DWC3_EP_END_TRANSFER_PENDING
check in ep_dequeue as well so if it is not set then cleanup the cancelled
list from there.

Change-Id: I575a38ba9dc9b3a6684d0973a49109f97e22f1b2
Signed-off-by: Udipto Goswami <ugoswami@codeaurora.org>
1 file changed