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 @@ -416,6 +416,10 @@ SYSCTL_INT(_hw_hn, OID_AUTO, share_tx_taskq, CTLFLAG_RDTUN, &hn_share_tx_taskq, 0, "Enable shared TX taskqueue"); +static int hn_tx_taskq_cnt = 1; +SYSCTL_INT(_hw_hn, OID_AUTO, tx_taskq_cnt, CTLFLAG_RDTUN, + &hn_tx_taskq_cnt, 0, "# of TX taskqueues"); + #ifndef HN_USE_TXDESC_BUFRING static int hn_use_txdesc_bufring = 0; #else @@ -465,7 +469,7 @@ &hn_tx_agg_pkts, 0, "Packet transmission aggregation packet limit"); static u_int hn_cpu_index; /* next CPU for channel */ -static struct taskqueue *hn_tx_taskq; /* shared TX taskqueue */ +static struct taskqueue **hn_tx_taskque;/* shared TX taskqueues */ static const uint8_t hn_rss_key_default[NDIS_HASH_KEYSIZE_TOEPLITZ] = { @@ -898,13 +902,21 @@ /* * Setup taskqueue for transmission. */ - if (hn_tx_taskq == NULL) { - sc->hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK, - taskqueue_thread_enqueue, &sc->hn_tx_taskq); - taskqueue_start_threads(&sc->hn_tx_taskq, 1, PI_NET, "%s tx", - device_get_nameunit(dev)); + if (hn_tx_taskque == NULL) { + int i; + + sc->hn_tx_taskqs = + malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), + M_DEVBUF, M_WAITOK); + for (i = 0; i < hn_tx_taskq_cnt; ++i) { + sc->hn_tx_taskqs[i] = taskqueue_create("hn_tx", + M_WAITOK, taskqueue_thread_enqueue, + &sc->hn_tx_taskqs[i]); + taskqueue_start_threads(&sc->hn_tx_taskqs[i], 1, PI_NET, + "%s tx%d", device_get_nameunit(dev), i); + } } else { - sc->hn_tx_taskq = hn_tx_taskq; + sc->hn_tx_taskqs = hn_tx_taskque; } /* @@ -1204,8 +1216,13 @@ hn_destroy_rx_data(sc); hn_destroy_tx_data(sc); - if (sc->hn_tx_taskq != hn_tx_taskq) - taskqueue_free(sc->hn_tx_taskq); + if (sc->hn_tx_taskqs != hn_tx_taskque) { + int i; + + for (i = 0; i < hn_tx_taskq_cnt; ++i) + taskqueue_free(sc->hn_tx_taskqs[i]); + free(sc->hn_tx_taskqs, M_DEVBUF); + } taskqueue_free(sc->hn_mgmt_taskq0); if (sc->hn_xact != NULL) { @@ -3295,7 +3312,7 @@ M_WAITOK, &txr->hn_tx_lock); #endif - txr->hn_tx_taskq = sc->hn_tx_taskq; + txr->hn_tx_taskq = sc->hn_tx_taskqs[id % hn_tx_taskq_cnt]; #ifdef HN_IFSTART_SUPPORT if (hn_use_if_start) { @@ -5334,6 +5351,15 @@ static void hn_tx_taskq_create(void *arg __unused) { + int i; + + /* + * Fix the # of TX taskqueues. + */ + if (hn_tx_taskq_cnt <= 0) + hn_tx_taskq_cnt = 1; + else if (hn_tx_taskq_cnt > mp_ncpus) + hn_tx_taskq_cnt = mp_ncpus; if (vm_guest != VM_GUEST_HV) return; @@ -5341,9 +5367,14 @@ if (!hn_share_tx_taskq) return; - hn_tx_taskq = taskqueue_create("hn_tx", M_WAITOK, - taskqueue_thread_enqueue, &hn_tx_taskq); - taskqueue_start_threads(&hn_tx_taskq, 1, PI_NET, "hn tx"); + hn_tx_taskque = malloc(hn_tx_taskq_cnt * sizeof(struct taskqueue *), + M_DEVBUF, M_WAITOK); + for (i = 0; i < hn_tx_taskq_cnt; ++i) { + hn_tx_taskque[i] = taskqueue_create("hn_tx", M_WAITOK, + taskqueue_thread_enqueue, &hn_tx_taskque[i]); + taskqueue_start_threads(&hn_tx_taskque[i], 1, PI_NET, + "hn tx%d", i); + } } SYSINIT(hn_txtq_create, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_tx_taskq_create, NULL); @@ -5352,8 +5383,13 @@ hn_tx_taskq_destroy(void *arg __unused) { - if (hn_tx_taskq != NULL) - taskqueue_free(hn_tx_taskq); + if (hn_tx_taskque != NULL) { + int i; + + for (i = 0; i < hn_tx_taskq_cnt; ++i) + taskqueue_free(hn_tx_taskque[i]); + free(hn_tx_taskque, M_DEVBUF); + } } SYSUNINIT(hn_txtq_destroy, SI_SUB_DRIVERS, SI_ORDER_SECOND, hn_tx_taskq_destroy, NULL); 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 @@ -192,7 +192,7 @@ int hn_chim_szmax; int hn_cpu; - struct taskqueue *hn_tx_taskq; + struct taskqueue **hn_tx_taskqs; struct sysctl_oid *hn_tx_sysctl_tree; struct sysctl_oid *hn_rx_sysctl_tree; struct vmbus_xact_ctx *hn_xact;