rtwn(4) may end up in tsleep(9) while suspending, as shown in dmesg:
Starting stack trace...
tsleep() at tsleep+0x117
rtwn_fw_reset() at rtwn_fw_reset+0x71
rtwn_stop() at rtwn_stop+0x198
rtwn_activate() at rtwn_activate+0x32
config_suspend() at config_suspend+0x37
config_activate_children() at config_activate_children+0x4d
pciactivate() at pciactivate+0x38
config_suspend() at config_suspend+0x37
config_activate_children() at config_activate_children+0x4d
ppbactivate() at ppbactivate+0x75
config_suspend() at config_suspend+0x37
config_activate_children() at config_activate_children+0x4d
pciactivate() at pciactivate+0x38
config_suspend() at config_suspend+0x37
config_activate_children() at config_activate_children+0x4d
config_suspend() at config_suspend+0x5c
acpi_sleep_state() at acpi_sleep_state+0x221
acpi_sleep_task() at acpi_sleep_task+0x13
acpi_dotask() at acpi_dotask+0x55
acpi_thread() at acpi_thread+0x11d
end trace frame: 0x0, count: 237
End of stack trace.
The culprit is this bit from rtwn_fw_reset():
/*
* We must sleep for one second to let the firmware settle.
* Accessing registers too early will hang the whole system.
*/
tsleep(®, 0, "rtwnrst", hz);
I remember this problem being horrible to track down while writing this
driver. I would not like to remove that tsleep or try to work around it
somehow. The chip is stupid and lets all PCI access hang while the firmware
is rebooting. I don't even want to know why (not that anyone outside Realtek
would know) and spend even more time trying to find other workarounds.
I'm just glad the driver even works.
So I'd rather bring the interface down during DVACT_QUIESCE to make
the tsleep legal. This makes the above dmesg messages go away.
Index: rtwn.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/rtwn.c,v
retrieving revision 1.1
diff -u -p -r1.1 rtwn.c
--- rtwn.c 9 Mar 2016 18:18:28 -0000 1.1
+++ rtwn.c 9 Mar 2016 19:14:28 -0000
@@ -283,7 +283,7 @@ rtwn_activate(struct rtwn_softc *sc, int
struct ifnet *ifp = &sc->sc_ic.ic_if;
switch (act) {
- case DVACT_SUSPEND:
+ case DVACT_QUIESCE: /* rtwn_stop() may sleep */
if (ifp->if_flags & IFF_RUNNING)
rtwn_stop(ifp);
break;