Hi, Baolin Wang <baolin.wang@xxxxxxxxxx> writes: >>>>>>>>> void dwc3_gadget_exit(struct dwc3 *dwc) >>>>>>>>> { >>>>>>>>> + int epnum; >>>>>>>>> + unsigned long flags; >>>>>>>>> + >>>>>>>>> + spin_lock_irqsave(&dwc->lock, flags); >>>>>>>>> + for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) { >>>>>>>>> + struct dwc3_ep *dep = dwc->eps[epnum]; >>>>>>>>> + >>>>>>>>> + if (!dep) >>>>>>>>> + continue; >>>>>>>>> + >>>>>>>>> + dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING; >>>>>>>>> + } >>>>>>>>> + spin_unlock_irqrestore(&dwc->lock, flags); >>>>>>>>> + >>>>>>>>> usb_del_gadget_udc(&dwc->gadget); >>>>>>>>> dwc3_gadget_free_endpoints(dwc); >>>>>>>> >>>>>>>> free endpoints is a better place for this. It's already going to free >>>>>>>> the memory anyway. Might as well clear all flags to 0 there. >>>>>>>> >>>>>>> >>>>>>> But it won't solve the deadlock issue. Since dwc3_gadget_free_endpoints() >>>>>>> is called after usb_del_gadget_udc() and the deadlock happens when >>>>>>> >>>>>>> usb_del_gadget_udc()->udc_stop()->dwc3_gadget_stop()->wait_event_lock_irq() >>>>>>> >>>>>>> and DWC3_EP_END_TRANSFER_PENDING flag is set. >>>>>> >>>>>> indeed. Iterating twice over the entire endpoint list seems >>>>>> wasteful. Perhaps we just shouldn't wait when removing the UDC since >>>>>> that's essentially what this patch will do, right? If you clear the flag >>>>>> before calling ->udc_stop(), this means the loop in dwc3_gadget_stop() >>>>>> will do nothing. Might as well remove it. >>>>>> >>>>> >>>>> This means that we will never wait for DWC3_EP_END_TRANSFER_PENDING to clear >>>>> in dwc3_gadget_stop() like we used to. This is perfectly fine, right? >>>>> >>>>> It makes sense to me as dwc3_gadget_stop() calls __dwc3_gadget_stop() which >>>>> masks all interrupts and nobody will ever clear that flag if it was set. >>>> >>>> I don't think so. It can not mask the endpoint events, please check >>>> the events which will be masked in DEVTEN register. The reason why we >>>> should wait for DWC3_EP_END_TRANSFER_PENDING to clear is that, >>>> sometimes the DWC3_DEPEVT_EPCMDCMPLT event will be triggered later >>>> than 100us, but now we may have freed the gadget irq which will cause >>>> crash. >>> >>> We could mask command complete events as soon as ->udc_stop() is called, >>> right? Hmm, actually, __dwc3_gadget_stop() already clears DEVTEN >>> completely. >> >> But which bit in DEVTEN says Endpoint events are disabled? > > When we set up the DWC3_DEPCMD_ENDTRANSFER command in > dwc3_stop_active_transfer(), we can do not set DWC3_DEPCMD_CMDIOC, > then there will no endpoint command complete interrupts I think. > > cmd |= DWC3_DEPCMD_CMDIOC; I remember some part of the databook mandating CMDIOC to be set. We could test it out without and see if anything blows up. I would, however, require a lengthy comment explaining that we're deviating from databook revision x.yya, section foobar because $reasons. :-) -- balbi
Attachment:
signature.asc
Description: PGP signature