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.

xhci: Decouple handling an event from checking for unhandled events

Some sequences, will require traversing through the entire event ring
without handling the event TRB. This is ideal for when secondary
interrupters that are utilized by external entities need to clean up the
interrupter's event rings during halting of the XHCI HCD.

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com>
Link: https://lore.kernel.org/r/20240217001017.29969-10-quic_wcheng@quicinc.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Mathias Nyman and committed by
Greg Kroah-Hartman
edc47759 84008be8

+19 -19
+19 -19
drivers/usb/host/xhci-ring.c
··· 2962 2962 } 2963 2963 2964 2964 /* 2965 - * This function handles all OS-owned events on the event ring. It may drop 2965 + * This function handles one OS-owned event on the event ring. It may drop 2966 2966 * xhci->lock between event processing (e.g. to pass up port status changes). 2967 - * Returns >0 for "possibly more events to process" (caller should call again), 2968 - * otherwise 0 if done. In future, <0 returns should indicate error code. 2969 2967 */ 2970 - static int xhci_handle_event(struct xhci_hcd *xhci, struct xhci_interrupter *ir) 2968 + static int xhci_handle_event_trb(struct xhci_hcd *xhci, struct xhci_interrupter *ir, 2969 + union xhci_trb *event) 2971 2970 { 2972 - union xhci_trb *event; 2973 2971 u32 trb_type; 2974 - 2975 - event = ir->event_ring->dequeue; 2976 - 2977 - if (!unhandled_event_trb(ir->event_ring)) 2978 - return 0; 2979 2972 2980 2973 trace_xhci_handle_event(ir->event_ring, &event->generic); 2981 2974 2982 2975 /* 2983 - * Barrier between reading the TRB_CYCLE (valid) flag above and any 2976 + * Barrier between reading the TRB_CYCLE (valid) flag before, and any 2984 2977 * speculative reads of the event's flags/data below. 2985 2978 */ 2986 2979 rmb(); ··· 3003 3010 * to make sure a watchdog timer didn't mark the host as non-responsive. 3004 3011 */ 3005 3012 if (xhci->xhc_state & XHCI_STATE_DYING) { 3006 - xhci_dbg(xhci, "xHCI host dying, returning from " 3007 - "event handler.\n"); 3008 - return 0; 3013 + xhci_dbg(xhci, "xHCI host dying, returning from event handler.\n"); 3014 + return -ENODEV; 3009 3015 } 3010 3016 3011 - /* Are there more items on the event ring? Caller will call us again to 3012 - * check. 3013 - */ 3014 - return 1; 3017 + return 0; 3015 3018 } 3016 3019 3017 3020 /* ··· 3057 3068 } 3058 3069 } 3059 3070 3071 + /* 3072 + * Handle all OS-owned events on an interrupter event ring. It may drop 3073 + * and reaquire xhci->lock between event processing. 3074 + */ 3060 3075 static int xhci_handle_events(struct xhci_hcd *xhci, struct xhci_interrupter *ir) 3061 3076 { 3062 3077 int event_loop = 0; 3078 + int err; 3063 3079 u64 temp; 3064 3080 3065 3081 xhci_clear_interrupt_pending(xhci, ir); ··· 3085 3091 return -ENODEV; 3086 3092 } 3087 3093 3088 - while (xhci_handle_event(xhci, ir) > 0) { 3094 + /* Process all OS owned event TRBs on this event ring */ 3095 + while (unhandled_event_trb(ir->event_ring)) { 3096 + err = xhci_handle_event_trb(xhci, ir, ir->event_ring->dequeue); 3097 + 3089 3098 /* 3090 3099 * If half a segment of events have been handled in one go then 3091 3100 * update ERDP, and force isoc trbs to interrupt more often ··· 3104 3107 3105 3108 /* Update SW event ring dequeue pointer */ 3106 3109 inc_deq(xhci, ir->event_ring); 3110 + 3111 + if (err) 3112 + break; 3107 3113 } 3108 3114 3109 3115 xhci_update_erst_dequeue(xhci, ir, true);