Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: dwc3: gadget: Reinitiate stream for all host NoStream behavior

There are too many different host behaviors when it comes to NoStream
handling, and not everyone follows the USB and xHCI spec. The DWC3
driver attempts to do some guess work to interop with different hosts,
but it can't cover everything. Let's keep it simple and treat every host
the same: just retry on NoStream after a 100ms of no response delay.
Note that some hosts cannot handle frequent retries. This may affect
performance on certain defective hosts, but NoStream is a rare
occurrence and interoperability is more important.

Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
Link: https://lore.kernel.org/r/b92ae94c86f01f165d5f178b7767898573b6dc75.1736819308.git.Thinh.Nguyen@synopsys.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Thinh Nguyen and committed by
Greg Kroah-Hartman
dcfe4374 f386bfad

+59 -53
+2 -1
drivers/usb/dwc3/core.h
··· 743 743 */ 744 744 struct dwc3_ep { 745 745 struct usb_ep endpoint; 746 + struct delayed_work nostream_work; 746 747 struct list_head cancelled_list; 747 748 struct list_head pending_list; 748 749 struct list_head started_list; ··· 766 765 #define DWC3_EP_WAIT_TRANSFER_COMPLETE BIT(7) 767 766 #define DWC3_EP_IGNORE_NEXT_NOSTREAM BIT(8) 768 767 #define DWC3_EP_FORCE_RESTART_STREAM BIT(9) 769 - #define DWC3_EP_FIRST_STREAM_PRIMED BIT(10) 768 + #define DWC3_EP_STREAM_PRIMED BIT(10) 770 769 #define DWC3_EP_PENDING_CLEAR_STALL BIT(11) 771 770 #define DWC3_EP_TXFIFO_RESIZED BIT(12) 772 771 #define DWC3_EP_DELAY_STOP BIT(13)
+57 -52
drivers/usb/dwc3/gadget.c
··· 996 996 997 997 /* 998 998 * All stream eps will reinitiate stream on NoStream 999 - * rejection until we can determine that the host can 1000 - * prime after the first transfer. 999 + * rejection. 1001 1000 * 1002 1001 * However, if the controller is capable of 1003 1002 * TXF_FLUSH_BYPASS, then IN direction endpoints will ··· 3299 3300 return dwc3_alloc_trb_pool(dep); 3300 3301 } 3301 3302 3303 + #define nostream_work_to_dep(w) (container_of(to_delayed_work(w), struct dwc3_ep, nostream_work)) 3304 + static void dwc3_nostream_work(struct work_struct *work) 3305 + { 3306 + struct dwc3_ep *dep = nostream_work_to_dep(work); 3307 + struct dwc3 *dwc = dep->dwc; 3308 + unsigned long flags; 3309 + 3310 + spin_lock_irqsave(&dwc->lock, flags); 3311 + if (dep->flags & DWC3_EP_STREAM_PRIMED) 3312 + goto out; 3313 + 3314 + if ((dep->flags & DWC3_EP_IGNORE_NEXT_NOSTREAM) || 3315 + (!DWC3_MST_CAPABLE(&dwc->hwparams) && 3316 + !(dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE))) 3317 + goto out; 3318 + /* 3319 + * If the host rejects a stream due to no active stream, by the 3320 + * USB and xHCI spec, the endpoint will be put back to idle 3321 + * state. When the host is ready (buffer added/updated), it will 3322 + * prime the endpoint to inform the usb device controller. This 3323 + * triggers the device controller to issue ERDY to restart the 3324 + * stream. However, some hosts don't follow this and keep the 3325 + * endpoint in the idle state. No prime will come despite host 3326 + * streams are updated, and the device controller will not be 3327 + * triggered to generate ERDY to move the next stream data. To 3328 + * workaround this and maintain compatibility with various 3329 + * hosts, force to reinitiate the stream until the host is ready 3330 + * instead of waiting for the host to prime the endpoint. 3331 + */ 3332 + if (DWC3_VER_IS_WITHIN(DWC32, 100A, ANY)) { 3333 + unsigned int cmd = DWC3_DGCMD_SET_ENDPOINT_PRIME; 3334 + 3335 + dwc3_send_gadget_generic_command(dwc, cmd, dep->number); 3336 + } else { 3337 + dep->flags |= DWC3_EP_DELAY_START; 3338 + dwc3_stop_active_transfer(dep, true, true); 3339 + spin_unlock_irqrestore(&dwc->lock, flags); 3340 + return; 3341 + } 3342 + out: 3343 + dep->flags &= ~DWC3_EP_IGNORE_NEXT_NOSTREAM; 3344 + spin_unlock_irqrestore(&dwc->lock, flags); 3345 + } 3346 + 3302 3347 static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum) 3303 3348 { 3304 3349 struct dwc3_ep *dep; ··· 3388 3345 INIT_LIST_HEAD(&dep->pending_list); 3389 3346 INIT_LIST_HEAD(&dep->started_list); 3390 3347 INIT_LIST_HEAD(&dep->cancelled_list); 3348 + INIT_DELAYED_WORK(&dep->nostream_work, dwc3_nostream_work); 3391 3349 3392 3350 dwc3_debugfs_create_endpoint_dir(dep); 3393 3351 ··· 3788 3744 static void dwc3_gadget_endpoint_stream_event(struct dwc3_ep *dep, 3789 3745 const struct dwc3_event_depevt *event) 3790 3746 { 3791 - struct dwc3 *dwc = dep->dwc; 3792 - 3793 3747 if (event->status == DEPEVT_STREAMEVT_FOUND) { 3794 - dep->flags |= DWC3_EP_FIRST_STREAM_PRIMED; 3795 - goto out; 3748 + cancel_delayed_work(&dep->nostream_work); 3749 + dep->flags |= DWC3_EP_STREAM_PRIMED; 3750 + dep->flags &= ~DWC3_EP_IGNORE_NEXT_NOSTREAM; 3751 + return; 3796 3752 } 3797 3753 3798 3754 /* Note: NoStream rejection event param value is 0 and not 0xFFFF */ 3799 3755 switch (event->parameters) { 3800 3756 case DEPEVT_STREAM_PRIME: 3801 - /* 3802 - * If the host can properly transition the endpoint state from 3803 - * idle to prime after a NoStream rejection, there's no need to 3804 - * force restarting the endpoint to reinitiate the stream. To 3805 - * simplify the check, assume the host follows the USB spec if 3806 - * it primed the endpoint more than once. 3807 - */ 3808 - if (dep->flags & DWC3_EP_FORCE_RESTART_STREAM) { 3809 - if (dep->flags & DWC3_EP_FIRST_STREAM_PRIMED) 3810 - dep->flags &= ~DWC3_EP_FORCE_RESTART_STREAM; 3811 - else 3812 - dep->flags |= DWC3_EP_FIRST_STREAM_PRIMED; 3813 - } 3814 - 3757 + cancel_delayed_work(&dep->nostream_work); 3758 + dep->flags |= DWC3_EP_STREAM_PRIMED; 3759 + dep->flags &= ~DWC3_EP_IGNORE_NEXT_NOSTREAM; 3815 3760 break; 3816 3761 case DEPEVT_STREAM_NOSTREAM: 3817 - if ((dep->flags & DWC3_EP_IGNORE_NEXT_NOSTREAM) || 3818 - !(dep->flags & DWC3_EP_FORCE_RESTART_STREAM) || 3819 - (!DWC3_MST_CAPABLE(&dwc->hwparams) && 3820 - !(dep->flags & DWC3_EP_WAIT_TRANSFER_COMPLETE))) 3821 - break; 3822 - 3823 - /* 3824 - * If the host rejects a stream due to no active stream, by the 3825 - * USB and xHCI spec, the endpoint will be put back to idle 3826 - * state. When the host is ready (buffer added/updated), it will 3827 - * prime the endpoint to inform the usb device controller. This 3828 - * triggers the device controller to issue ERDY to restart the 3829 - * stream. However, some hosts don't follow this and keep the 3830 - * endpoint in the idle state. No prime will come despite host 3831 - * streams are updated, and the device controller will not be 3832 - * triggered to generate ERDY to move the next stream data. To 3833 - * workaround this and maintain compatibility with various 3834 - * hosts, force to reinitiate the stream until the host is ready 3835 - * instead of waiting for the host to prime the endpoint. 3836 - */ 3837 - if (DWC3_VER_IS_WITHIN(DWC32, 100A, ANY)) { 3838 - unsigned int cmd = DWC3_DGCMD_SET_ENDPOINT_PRIME; 3839 - 3840 - dwc3_send_gadget_generic_command(dwc, cmd, dep->number); 3841 - } else { 3842 - dep->flags |= DWC3_EP_DELAY_START; 3843 - dwc3_stop_active_transfer(dep, true, true); 3844 - return; 3845 - } 3762 + dep->flags &= ~DWC3_EP_STREAM_PRIMED; 3763 + if (dep->flags & DWC3_EP_FORCE_RESTART_STREAM) 3764 + queue_delayed_work(system_wq, &dep->nostream_work, 3765 + msecs_to_jiffies(100)); 3846 3766 break; 3847 3767 } 3848 - 3849 - out: 3850 - dep->flags &= ~DWC3_EP_IGNORE_NEXT_NOSTREAM; 3851 3768 } 3852 3769 3853 3770 static void dwc3_endpoint_interrupt(struct dwc3 *dwc,