Index: head/sys/dev/hyperv/netvsc/hn_nvs.c =================================================================== --- head/sys/dev/hyperv/netvsc/hn_nvs.c +++ head/sys/dev/hyperv/netvsc/hn_nvs.c @@ -109,7 +109,10 @@ vmbus_xact_deactivate(xact); return (NULL); } - hdr = vmbus_xact_wait(xact, &resplen); + if (HN_CAN_SLEEP(sc)) + hdr = vmbus_xact_wait(xact, &resplen); + else + hdr = vmbus_xact_busywait(xact, &resplen); /* * Check this NVS response message. Index: head/sys/dev/hyperv/netvsc/hn_rndis.c =================================================================== --- head/sys/dev/hyperv/netvsc/hn_rndis.c +++ head/sys/dev/hyperv/netvsc/hn_rndis.c @@ -232,7 +232,10 @@ if_printf(sc->hn_ifp, "RNDIS ctrl send failed: %d\n", error); return (NULL); } - return (vmbus_xact_wait(xact, comp_len)); + if (HN_CAN_SLEEP(sc)) + return (vmbus_xact_wait(xact, comp_len)); + else + return (vmbus_xact_busywait(xact, comp_len)); } static const void * Index: head/sys/dev/hyperv/netvsc/if_hn.c =================================================================== --- head/sys/dev/hyperv/netvsc/if_hn.c +++ head/sys/dev/hyperv/netvsc/if_hn.c @@ -149,7 +149,11 @@ sx_init(&(sc)->hn_lock, device_get_nameunit((sc)->hn_dev)) #define HN_LOCK_DESTROY(sc) sx_destroy(&(sc)->hn_lock) #define HN_LOCK_ASSERT(sc) sx_assert(&(sc)->hn_lock, SA_XLOCKED) -#define HN_LOCK(sc) sx_xlock(&(sc)->hn_lock) +#define HN_LOCK(sc) \ +do { \ + while (sx_try_xlock(&(sc)->hn_lock) == 0) \ + DELAY(1000); \ +} while (0) #define HN_UNLOCK(sc) sx_xunlock(&(sc)->hn_lock) #define HN_CSUM_IP_MASK (CSUM_IP | CSUM_IP_TCP | CSUM_IP_UDP) @@ -667,18 +671,10 @@ filter = NDIS_PACKET_TYPE_DIRECTED; if (ifp->if_flags & IFF_BROADCAST) filter |= NDIS_PACKET_TYPE_BROADCAST; -#ifdef notyet - /* - * See the comment in SIOCADDMULTI/SIOCDELMULTI. - */ /* TODO: support multicast list */ if ((ifp->if_flags & IFF_ALLMULTI) || !TAILQ_EMPTY(&ifp->if_multiaddrs)) filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; -#else - /* Always enable ALLMULTI */ - filter |= NDIS_PACKET_TYPE_ALL_MULTICAST; -#endif } if (sc->hn_rx_filter != filter) { @@ -2338,10 +2334,18 @@ } if (ifp->if_flags & IFF_UP) { - if (ifp->if_drv_flags & IFF_DRV_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + /* + * Caller meight hold mutex, e.g. + * bpf; use busy-wait for the RNDIS + * reply. + */ + HN_NO_SLEEPING(sc); hn_set_rxfilter(sc); - else + HN_SLEEPING_OK(sc); + } else { hn_init_locked(sc); + } } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) hn_stop(sc); @@ -2402,27 +2406,23 @@ case SIOCADDMULTI: case SIOCDELMULTI: -#ifdef notyet - /* - * XXX - * Multicast uses mutex, while RNDIS RX filter setting - * sleeps. We workaround this by always enabling - * ALLMULTI. ALLMULTI would actually always be on, even - * if we supported the SIOCADDMULTI/SIOCDELMULTI, since - * we don't support multicast address list configuration - * for this driver. - */ HN_LOCK(sc); if ((sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) == 0) { HN_UNLOCK(sc); break; } - if (ifp->if_drv_flags & IFF_DRV_RUNNING) + if (ifp->if_drv_flags & IFF_DRV_RUNNING) { + /* + * Multicast uses mutex; use busy-wait for + * the RNDIS reply. + */ + HN_NO_SLEEPING(sc); hn_set_rxfilter(sc); + HN_SLEEPING_OK(sc); + } HN_UNLOCK(sc); -#endif break; case SIOCSIFMEDIA: Index: head/sys/dev/hyperv/netvsc/if_hnvar.h =================================================================== --- head/sys/dev/hyperv/netvsc/if_hnvar.h +++ head/sys/dev/hyperv/netvsc/if_hnvar.h @@ -236,6 +236,20 @@ #define HN_FLAG_HAS_RSSKEY 0x0004 #define HN_FLAG_HAS_RSSIND 0x0008 #define HN_FLAG_SYNTH_ATTACHED 0x0010 +#define HN_FLAG_NO_SLEEPING 0x0020 + +#define HN_NO_SLEEPING(sc) \ +do { \ + (sc)->hn_flags |= HN_FLAG_NO_SLEEPING; \ +} while (0) + +#define HN_SLEEPING_OK(sc) \ +do { \ + (sc)->hn_flags &= ~HN_FLAG_NO_SLEEPING; \ +} while (0) + +#define HN_CAN_SLEEP(sc) \ + (((sc)->hn_flags & HN_FLAG_NO_SLEEPING) == 0) #define HN_CAP_VLAN 0x0001 #define HN_CAP_MTU 0x0002