Sun Apr 9 20:41:29 2023 UTC ()
xhci(4): Avoid crash in suspend/resume/resume if first resume fails.

Rather than try to recover from this, just make new commands fail so
at least we don't deadlock.

XXX pullup-9
XXX pullup-10


(riastradh)
diff -r1.176 -r1.177 src/sys/dev/usb/xhci.c
diff -r1.23 -r1.24 src/sys/dev/usb/xhcivar.h

cvs diff -r1.176 -r1.177 src/sys/dev/usb/xhci.c (expand / switch to unified diff)

--- src/sys/dev/usb/xhci.c 2023/04/07 09:39:48 1.176
+++ src/sys/dev/usb/xhci.c 2023/04/09 20:41:28 1.177
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: xhci.c,v 1.176 2023/04/07 09:39:48 riastradh Exp $ */ 1/* $NetBSD: xhci.c,v 1.177 2023/04/09 20:41:28 riastradh Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2013 Jonathan A. Kollasch 4 * Copyright (c) 2013 Jonathan A. Kollasch
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -24,27 +24,27 @@ @@ -24,27 +24,27 @@
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29/* 29/*
30 * USB rev 2.0 and rev 3.1 specification 30 * USB rev 2.0 and rev 3.1 specification
31 * http://www.usb.org/developers/docs/ 31 * http://www.usb.org/developers/docs/
32 * xHCI rev 1.1 specification 32 * xHCI rev 1.1 specification
33 * http://www.intel.com/technology/usb/spec.htm 33 * http://www.intel.com/technology/usb/spec.htm
34 */ 34 */
35 35
36#include <sys/cdefs.h> 36#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.176 2023/04/07 09:39:48 riastradh Exp $"); 37__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.177 2023/04/09 20:41:28 riastradh Exp $");
38 38
39#ifdef _KERNEL_OPT 39#ifdef _KERNEL_OPT
40#include "opt_usb.h" 40#include "opt_usb.h"
41#endif 41#endif
42 42
43#include <sys/param.h> 43#include <sys/param.h>
44#include <sys/systm.h> 44#include <sys/systm.h>
45#include <sys/kernel.h> 45#include <sys/kernel.h>
46#include <sys/kmem.h> 46#include <sys/kmem.h>
47#include <sys/device.h> 47#include <sys/device.h>
48#include <sys/select.h> 48#include <sys/select.h>
49#include <sys/proc.h> 49#include <sys/proc.h>
50#include <sys/queue.h> 50#include <sys/queue.h>
@@ -690,26 +690,27 @@ xhci_suspend(device_t self, const pmf_qu @@ -690,26 +690,27 @@ xhci_suspend(device_t self, const pmf_qu
690 int port; 690 int port;
691 uint32_t v; 691 uint32_t v;
692 usbd_status err; 692 usbd_status err;
693 bool ok = false; 693 bool ok = false;
694 694
695 XHCIHIST_FUNC(); XHCIHIST_CALLED(); 695 XHCIHIST_FUNC(); XHCIHIST_CALLED();
696 696
697 /* 697 /*
698 * Block issuance of new commands, and wait for all pending 698 * Block issuance of new commands, and wait for all pending
699 * commands to complete. 699 * commands to complete.
700 */ 700 */
701 mutex_enter(&sc->sc_lock); 701 mutex_enter(&sc->sc_lock);
702 KASSERT(sc->sc_suspender == NULL); 702 KASSERT(sc->sc_suspender == NULL);
 703 KASSERT(!sc->sc_suspendresume_failed);
703 sc->sc_suspender = curlwp; 704 sc->sc_suspender = curlwp;
704 while (sc->sc_command_addr != 0) 705 while (sc->sc_command_addr != 0)
705 cv_wait(&sc->sc_cmdbusy_cv, &sc->sc_lock); 706 cv_wait(&sc->sc_cmdbusy_cv, &sc->sc_lock);
706 mutex_exit(&sc->sc_lock); 707 mutex_exit(&sc->sc_lock);
707 708
708 /* 709 /*
709 * Block roothub xfers which might touch portsc registers until 710 * Block roothub xfers which might touch portsc registers until
710 * we're done suspending. 711 * we're done suspending.
711 */ 712 */
712 mutex_enter(&sc->sc_rhlock); 713 mutex_enter(&sc->sc_rhlock);
713 714
714 /* 715 /*
715 * xHCI Requirements Specification 1.2, May 2019, Sec. 4.23.2: 716 * xHCI Requirements Specification 1.2, May 2019, Sec. 4.23.2:
@@ -885,49 +886,62 @@ xhci_suspend(device_t self, const pmf_qu @@ -885,49 +886,62 @@ xhci_suspend(device_t self, const pmf_qu
885 * successfully.' 886 * successfully.'
886 */ 887 */
887 if (xhci_op_read_4(sc, XHCI_USBSTS) & XHCI_STS_SRE) { 888 if (xhci_op_read_4(sc, XHCI_USBSTS) & XHCI_STS_SRE) {
888 device_printf(self, "suspend error, USBSTS.SRE\n"); 889 device_printf(self, "suspend error, USBSTS.SRE\n");
889 goto out; 890 goto out;
890 } 891 }
891 892
892 /* Success! */ 893 /* Success! */
893 ok = true; 894 ok = true;
894 895
895out: mutex_exit(&sc->sc_rhlock); 896out: mutex_exit(&sc->sc_rhlock);
896 if (!ok) { 897 if (!ok) {
897 /* 898 /*
898 * If suspend failed, resume command issuance. 899 * If suspend failed, stop holding up command issuance
 900 * and make it fail instead.
899 */ 901 */
900 mutex_enter(&sc->sc_lock); 902 mutex_enter(&sc->sc_lock);
901 KASSERT(sc->sc_suspender == curlwp); 903 KASSERT(sc->sc_suspender == curlwp);
902 sc->sc_suspender = NULL; 904 sc->sc_suspender = NULL;
 905 sc->sc_suspendresume_failed = true;
903 cv_broadcast(&sc->sc_cmdbusy_cv); 906 cv_broadcast(&sc->sc_cmdbusy_cv);
904 mutex_exit(&sc->sc_lock); 907 mutex_exit(&sc->sc_lock);
905 } 908 }
906 return ok; 909 return ok;
907} 910}
908 911
909bool 912bool
910xhci_resume(device_t self, const pmf_qual_t *qual) 913xhci_resume(device_t self, const pmf_qual_t *qual)
911{ 914{
912 struct xhci_softc * const sc = device_private(self); 915 struct xhci_softc * const sc = device_private(self);
913 size_t i, j, bn, dci; 916 size_t i, j, bn, dci;
914 int port; 917 int port;
915 uint32_t v; 918 uint32_t v;
916 bool ok = false; 919 bool ok = false;
917 920
918 XHCIHIST_FUNC(); XHCIHIST_CALLED(); 921 XHCIHIST_FUNC(); XHCIHIST_CALLED();
919 922
 923 /*
 924 * If resume had previously failed, just try again. Can't make
 925 * things worse, probably.
 926 */
 927 mutex_enter(&sc->sc_lock);
 928 if (sc->sc_suspendresume_failed) {
 929 KASSERT(sc->sc_suspender == NULL);
 930 sc->sc_suspender = curlwp;
 931 sc->sc_suspendresume_failed = false;
 932 }
920 KASSERT(sc->sc_suspender); 933 KASSERT(sc->sc_suspender);
 934 mutex_exit(&sc->sc_lock);
921 935
922 /* 936 /*
923 * Block roothub xfers which might touch portsc registers until 937 * Block roothub xfers which might touch portsc registers until
924 * we're done resuming. 938 * we're done resuming.
925 */ 939 */
926 mutex_enter(&sc->sc_rhlock); 940 mutex_enter(&sc->sc_rhlock);
927 941
928 /* 942 /*
929 * xHCI Requirements Specification 1.2, May 2019, Sec. 4.23.2: 943 * xHCI Requirements Specification 1.2, May 2019, Sec. 4.23.2:
930 * xHCI Power Management, p. 343 944 * xHCI Power Management, p. 343
931 * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf#page=343 945 * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf#page=343
932 */ 946 */
933 947
@@ -1101,26 +1115,27 @@ xhci_resume(device_t self, const pmf_qua @@ -1101,26 +1115,27 @@ xhci_resume(device_t self, const pmf_qua
1101 1115
1102 /* Success! */ 1116 /* Success! */
1103 ok = true; 1117 ok = true;
1104 1118
1105out: /* 1119out: /*
1106 * Resume command issuance. If the hardware failed to resume, 1120 * Resume command issuance. If the hardware failed to resume,
1107 * well, tough -- deadlocking because everything is held up on 1121 * well, tough -- deadlocking because everything is held up on
1108 * the suspension, with no opportunity to detach, isn't better 1122 * the suspension, with no opportunity to detach, isn't better
1109 * than timing out waiting for dead hardware. 1123 * than timing out waiting for dead hardware.
1110 */ 1124 */
1111 mutex_enter(&sc->sc_lock); 1125 mutex_enter(&sc->sc_lock);
1112 KASSERT(sc->sc_suspender); 1126 KASSERT(sc->sc_suspender);
1113 sc->sc_suspender = NULL; 1127 sc->sc_suspender = NULL;
 1128 sc->sc_suspendresume_failed = !ok;
1114 cv_broadcast(&sc->sc_cmdbusy_cv); 1129 cv_broadcast(&sc->sc_cmdbusy_cv);
1115 mutex_exit(&sc->sc_lock); 1130 mutex_exit(&sc->sc_lock);
1116 1131
1117 mutex_exit(&sc->sc_rhlock); 1132 mutex_exit(&sc->sc_rhlock);
1118 return ok; 1133 return ok;
1119} 1134}
1120 1135
1121bool 1136bool
1122xhci_shutdown(device_t self, int flags) 1137xhci_shutdown(device_t self, int flags)
1123{ 1138{
1124 return false; 1139 return false;
1125} 1140}
1126 1141
@@ -3207,26 +3222,28 @@ xhci_do_command_locked(struct xhci_softc @@ -3207,26 +3222,28 @@ xhci_do_command_locked(struct xhci_softc
3207 struct xhci_ring * const cr = sc->sc_cr; 3222 struct xhci_ring * const cr = sc->sc_cr;
3208 usbd_status err; 3223 usbd_status err;
3209 3224
3210 XHCIHIST_FUNC(); 3225 XHCIHIST_FUNC();
3211 XHCIHIST_CALLARGS("input: 0x%016jx 0x%08jx 0x%08jx", 3226 XHCIHIST_CALLARGS("input: 0x%016jx 0x%08jx 0x%08jx",
3212 trb->trb_0, trb->trb_2, trb->trb_3, 0); 3227 trb->trb_0, trb->trb_2, trb->trb_3, 0);
3213 3228
3214 KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx"); 3229 KASSERTMSG(!cpu_intr_p() && !cpu_softintr_p(), "called from intr ctx");
3215 KASSERT(mutex_owned(&sc->sc_lock)); 3230 KASSERT(mutex_owned(&sc->sc_lock));
3216 3231
3217 while (sc->sc_command_addr != 0 || 3232 while (sc->sc_command_addr != 0 ||
3218 (sc->sc_suspender != NULL && sc->sc_suspender != curlwp)) 3233 (sc->sc_suspender != NULL && sc->sc_suspender != curlwp))
3219 cv_wait(&sc->sc_cmdbusy_cv, &sc->sc_lock); 3234 cv_wait(&sc->sc_cmdbusy_cv, &sc->sc_lock);
 3235 if (sc->sc_suspendresume_failed)
 3236 return USBD_IOERROR;
3220 3237
3221 /* 3238 /*
3222 * If enqueue pointer points at last of ring, it's Link TRB, 3239 * If enqueue pointer points at last of ring, it's Link TRB,
3223 * command TRB will be stored in 0th TRB. 3240 * command TRB will be stored in 0th TRB.
3224 */ 3241 */
3225 if (cr->xr_ep == cr->xr_ntrb - 1) 3242 if (cr->xr_ep == cr->xr_ntrb - 1)
3226 sc->sc_command_addr = xhci_ring_trbp(cr, 0); 3243 sc->sc_command_addr = xhci_ring_trbp(cr, 0);
3227 else 3244 else
3228 sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep); 3245 sc->sc_command_addr = xhci_ring_trbp(cr, cr->xr_ep);
3229 3246
3230 sc->sc_resultpending = true; 3247 sc->sc_resultpending = true;
3231 3248
3232 mutex_enter(&cr->xr_lock); 3249 mutex_enter(&cr->xr_lock);

cvs diff -r1.23 -r1.24 src/sys/dev/usb/xhcivar.h (expand / switch to unified diff)

--- src/sys/dev/usb/xhcivar.h 2023/04/07 09:39:48 1.23
+++ src/sys/dev/usb/xhcivar.h 2023/04/09 20:41:29 1.24
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: xhcivar.h,v 1.23 2023/04/07 09:39:48 riastradh Exp $ */ 1/* $NetBSD: xhcivar.h,v 1.24 2023/04/09 20:41:29 riastradh Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2013 Jonathan A. Kollasch 4 * Copyright (c) 2013 Jonathan A. Kollasch
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -130,26 +130,27 @@ struct xhci_softc { @@ -130,26 +130,27 @@ struct xhci_softc {
130 130
131 usb_dma_t sc_eventst_dma; 131 usb_dma_t sc_eventst_dma;
132 usb_dma_t sc_dcbaa_dma; 132 usb_dma_t sc_dcbaa_dma;
133 usb_dma_t sc_spbufarray_dma; 133 usb_dma_t sc_spbufarray_dma;
134 usb_dma_t *sc_spbuf_dma; 134 usb_dma_t *sc_spbuf_dma;
135 135
136 kcondvar_t sc_cmdbusy_cv; 136 kcondvar_t sc_cmdbusy_cv;
137 kcondvar_t sc_command_cv; 137 kcondvar_t sc_command_cv;
138 bus_addr_t sc_command_addr; 138 bus_addr_t sc_command_addr;
139 struct xhci_soft_trb sc_result_trb; 139 struct xhci_soft_trb sc_result_trb;
140 bool sc_resultpending; 140 bool sc_resultpending;
141 141
142 bool sc_dying; 142 bool sc_dying;
 143 bool sc_suspendresume_failed;
143 struct lwp *sc_suspender; 144 struct lwp *sc_suspender;
144 145
145 void (*sc_vendor_init)(struct xhci_softc *); 146 void (*sc_vendor_init)(struct xhci_softc *);
146 int (*sc_vendor_port_status)(struct xhci_softc *, uint32_t, int); 147 int (*sc_vendor_port_status)(struct xhci_softc *, uint32_t, int);
147 148
148 int sc_quirks; 149 int sc_quirks;
149#define XHCI_QUIRK_INTEL __BIT(0) /* Intel xhci chip */ 150#define XHCI_QUIRK_INTEL __BIT(0) /* Intel xhci chip */
150#define XHCI_DEFERRED_START __BIT(1) 151#define XHCI_DEFERRED_START __BIT(1)
151 uint32_t sc_hcc; /* copy of HCCPARAMS1 */ 152 uint32_t sc_hcc; /* copy of HCCPARAMS1 */
152 uint32_t sc_hcc2; /* copy of HCCPARAMS2 */ 153 uint32_t sc_hcc2; /* copy of HCCPARAMS2 */
153 154
154 struct xhci_registers { 155 struct xhci_registers {
155 uint32_t usbcmd; 156 uint32_t usbcmd;