@@ -180,21 +180,21 @@ static void bce_vhci_transfer_queue_completion(struct bce_queue_sq *sq)
180180 */
181181 if (c -> status == BCE_COMPLETION_ABORTED ) { /* We flushed the queue */
182182 pr_debug ("bce-vhci: [%02x] Got an abort completion\n" , q -> endp_addr );
183- if (is_sq_out && atomic_dec_and_test (& q -> sq_out_pending ))
183+ if (is_sq_out && atomic_dec_if_positive (& q -> sq_out_pending ) == 0 )
184184 wake_up (& q -> sq_out_wait_queue );
185185 bce_notify_submission_complete (sq );
186186 continue ;
187187 }
188188 if (list_empty (& q -> endp -> urb_list )) {
189189 pr_err ("bce-vhci: [%02x] Got a completion while no requests are pending\n" , q -> endp_addr );
190- if (is_sq_out && atomic_dec_and_test (& q -> sq_out_pending ))
190+ if (is_sq_out && atomic_dec_if_positive (& q -> sq_out_pending ) == 0 )
191191 wake_up (& q -> sq_out_wait_queue );
192192 continue ;
193193 }
194194 pr_debug ("bce-vhci: [%02x] Got a transfer queue completion\n" , q -> endp_addr );
195195 urb = list_first_entry (& q -> endp -> urb_list , struct urb , urb_list );
196196 bce_vhci_urb_transfer_completion (urb -> hcpriv , c );
197- if (is_sq_out && atomic_dec_and_test (& q -> sq_out_pending ))
197+ if (is_sq_out && atomic_dec_if_positive (& q -> sq_out_pending ) == 0 )
198198 wake_up (& q -> sq_out_wait_queue );
199199 bce_notify_submission_complete (sq );
200200 }
@@ -204,50 +204,66 @@ static void bce_vhci_transfer_queue_completion(struct bce_queue_sq *sq)
204204}
205205
206206/* Timeout for waiting on pending output requests during pause */
207- #define BCE_VHCI_PAUSE_TIMEOUT_MS 5000
207+ #define BCE_VHCI_PAUSE_TIMEOUT_MS 2000
208208
209209int bce_vhci_transfer_queue_do_pause (struct bce_vhci_transfer_queue * q )
210210{
211211 unsigned long flags ;
212212 int status ;
213213 int pending ;
214214 long timeout ;
215- u8 endp_addr = (u8 ) (q -> endp -> desc .bEndpointAddress & 0x8F );
215+
216+ pr_info ("bce-vhci: [%02x] pause: starting (dev=%d)\n" , q -> endp_addr , q -> dev_addr );
216217
217218 spin_lock_irqsave (& q -> urb_lock , flags );
218219 q -> active = false;
219220 spin_unlock_irqrestore (& q -> urb_lock , flags );
220221 bce_vhci_transfer_queue_remove_pending (q );
221222
222- if ((status = bce_vhci_cmd_endpoint_set_state (
223- & q -> vhci -> cq , q -> dev_addr , endp_addr , BCE_VHCI_ENDPOINT_PAUSED , & q -> state )))
224- return status ;
225- if (q -> state != BCE_VHCI_ENDPOINT_PAUSED )
226- return - EINVAL ;
227-
228- if (q -> sq_in )
229- bce_cmd_flush_memory_queue (q -> vhci -> dev -> cmd_cmdq , (u16 ) q -> sq_in -> qid );
230-
223+ /*
224+ * Wait for pending output transfers to COMPLETE before pausing/flushing.
225+ * This ensures commands like keyboard backlight off actually reach the T2
226+ * before we abort remaining transfers. Without this, the backlight command
227+ * gets aborted by flush and the keyboard stays lit during suspend.
228+ */
231229 if (q -> sq_out ) {
232- bce_cmd_flush_memory_queue (q -> vhci -> dev -> cmd_cmdq , (u16 ) q -> sq_out -> qid );
233- /*
234- * Suspend/resume fix: Wait for all pending output DMA transfers to
235- * complete before returning. This prevents use-after-free when the
236- * queue is destroyed while transfers are still in flight.
237- */
238230 pending = atomic_read (& q -> sq_out_pending );
231+ pr_info ("bce-vhci: [%02x] pause: %d pending outputs, waiting for completion\n" ,
232+ q -> endp_addr , pending );
239233 if (pending > 0 ) {
240234 timeout = wait_event_timeout (q -> sq_out_wait_queue ,
241235 atomic_read (& q -> sq_out_pending ) == 0 ,
242236 msecs_to_jiffies (BCE_VHCI_PAUSE_TIMEOUT_MS ));
243237 if (timeout == 0 ) {
244238 pending = atomic_read (& q -> sq_out_pending );
245239 if (pending > 0 )
246- pr_warn ("bce-vhci: [%02x] Timeout waiting for %d pending output requests \n" ,
240+ pr_warn ("bce-vhci: [%02x] pause: TIMEOUT waiting for %d pending outputs \n" ,
247241 q -> endp_addr , pending );
242+ } else {
243+ pr_info ("bce-vhci: [%02x] pause: pending outputs completed\n" , q -> endp_addr );
248244 }
249245 }
250246 }
247+
248+ pr_info ("bce-vhci: [%02x] pause: setting endpoint state to PAUSED\n" , q -> endp_addr );
249+ if ((status = bce_vhci_cmd_endpoint_set_state (
250+ & q -> vhci -> cq , q -> dev_addr , q -> endp_addr , BCE_VHCI_ENDPOINT_PAUSED , & q -> state ))) {
251+ pr_err ("bce-vhci: [%02x] pause: set_state failed with %d\n" , q -> endp_addr , status );
252+ return status ;
253+ }
254+ if (q -> state != BCE_VHCI_ENDPOINT_PAUSED ) {
255+ pr_err ("bce-vhci: [%02x] pause: unexpected state %d\n" , q -> endp_addr , q -> state );
256+ return - EINVAL ;
257+ }
258+
259+ pr_info ("bce-vhci: [%02x] pause: flushing queues\n" , q -> endp_addr );
260+ if (q -> sq_in )
261+ bce_cmd_flush_memory_queue (q -> vhci -> dev -> cmd_cmdq , (u16 ) q -> sq_in -> qid );
262+
263+ if (q -> sq_out )
264+ bce_cmd_flush_memory_queue (q -> vhci -> dev -> cmd_cmdq , (u16 ) q -> sq_out -> qid );
265+
266+ pr_info ("bce-vhci: [%02x] pause: done\n" , q -> endp_addr );
251267 return 0 ;
252268}
253269
@@ -259,10 +275,9 @@ int bce_vhci_transfer_queue_do_resume(struct bce_vhci_transfer_queue *q)
259275 int status ;
260276 struct urb * urb , * urbt ;
261277 struct bce_vhci_urb * vurb ;
262- u8 endp_addr = (u8 ) (q -> endp -> desc .bEndpointAddress & 0x8F );
263278
264279 if ((status = bce_vhci_cmd_endpoint_set_state (
265- & q -> vhci -> cq , q -> dev_addr , endp_addr , BCE_VHCI_ENDPOINT_ACTIVE , & q -> state )))
280+ & q -> vhci -> cq , q -> dev_addr , q -> endp_addr , BCE_VHCI_ENDPOINT_ACTIVE , & q -> state )))
266281 return status ;
267282 if (q -> state != BCE_VHCI_ENDPOINT_ACTIVE )
268283 return - EINVAL ;
0 commit comments