CPU A dwc3_set_mode(DWC3_GCTL_PRTCAP_HOST) // first role switch event spin_lock_irqsave(&dwc->lock, flags); dwc->desired_dr_role = mode; // DWC3_GCTL_PRTCAP_HOST spin_unlock_irqrestore(&dwc->lock, flags); queue_work(system_freezable_wq, &dwc->drd_work); // true, schedules __dwc3_set_mode CPU B __dwc3_set_mode // .... spin_lock_irqsave(&dwc->lock, flags); dwc3_set_prtcap(dwc, dwc->desired_dr_role); // DWC3_GCTL_PRTCAP_HOST spin_unlock_irqrestore(&dwc->lock, flags); CPU A dwc3_set_mode(DWC3_GCTL_PRTCAP_DEVICE) // second role switch event spin_lock_irqsave(&dwc->lock, flags); dwc->desired_dr_role = mode; // DWC3_GCTL_PRTCAP_DEVICE spin_unlock_irqrestore(&dwc->lock, flags); CPU B (continues running __dwc3_set_mode) switch (dwc->desired_dr_role) { // DWC3_GCTL_PRTCAP_DEVICE case DWC3_GCTL_PRTCAP_HOST: // not executed since desired_dr_role is DWC3_GCTL_PRTCAP_DEVICE now break; CPU A (continues running dwc3_set_mode) queue_work(system_freezable_wq, &dwc->drd_work); // __dwc3_set_mode is still running CPU B (continues running __dwc3_set_mode) case DWC3_GCTL_PRTCAP_DEVICE: // .... ret = dwc3_gadget_init(dwc);