Index: share/man/man4/em.4 =================================================================== --- share/man/man4/em.4 +++ share/man/man4/em.4 @@ -45,6 +45,14 @@ .Cd "device em" .Ed .Pp +Optional multiqueue support is available via the following kernel +compile options: +.Bd -ragged -offset indent +.Cd "options EM_MULTIQUEUE" +.Ed +.Pp +Note: Activating EM_MULTIQUEUE support is not supported by Intel. +.Pp Alternatively, to load the driver as a module at boot time, place the following line in .Xr loader.conf 5 : @@ -197,6 +205,14 @@ prompt before booting the kernel or stored in .Xr loader.conf 5 . .Bl -tag -width indent +.It Va hw.em.eee_setting +Disable or Enable Energy Efficient Ethernet. Default 1 (disabled). +.It Va hw.em.msix +Enable or Disable MSI-X style interrupts. Default 1 (on). +.It Va hw.em.smart_pwr_down +Enable or Disable smart power down features on newer adapters. Default 0 (off). +.It Va hw.em.sbp +Show bad packets when in promiscuous mode. Default 0 (off). .It Va hw.em.rxd Number of receive descriptors allocated by the driver. The default value is 1024 for adapters newer than 82547, @@ -228,6 +244,11 @@ .Va hw.em.tx_int_delay is non-zero, this tunable limits the maximum delay in which a transmit interrupt is generated. +.It Va hw.em.num_rx_queues +.It Va hw.em.num_tx_queues +Number of h/w queues that we will run on this adapter. Max 2. Defaults to 1. +Only valid with kernel configuration +.Cd "options EM_MULTIQUEUE". .El .Sh FILES .Bl -tag -width /dev/led/em* Index: sys/conf/NOTES =================================================================== --- sys/conf/NOTES +++ sys/conf/NOTES @@ -2978,6 +2978,9 @@ # Module to enable execution of application via emulators like QEMU options IMAGACT_BINMISC +# Intel em(4) driver +options EM_MULTIQUEUE # Activate multiqueue features/disable MSI-X + # zlib I/O stream support # This enables support for compressed core dumps. options GZIO Index: sys/conf/options =================================================================== --- sys/conf/options +++ sys/conf/options @@ -935,3 +935,6 @@ RANDOM_YARROW opt_random.h RANDOM_FORTUNA opt_random.h RANDOM_DEBUG opt_random.h + +# Intel em(4) driver +EM_MULTIQUEUE opt_em.h Index: sys/dev/e1000/e1000_defines.h =================================================================== --- sys/dev/e1000/e1000_defines.h +++ sys/dev/e1000/e1000_defines.h @@ -158,10 +158,12 @@ E1000_RXDEXT_STATERR_CXE | \ E1000_RXDEXT_STATERR_RXE) +#define E1000_MRQC_RSS_ENABLE_2Q 0x00000001 #define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000 #define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000 #define E1000_MRQC_RSS_FIELD_IPV4 0x00020000 #define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000 +#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000 #define E1000_MRQC_RSS_FIELD_IPV6 0x00100000 #define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000 Index: sys/dev/e1000/if_em.h =================================================================== --- sys/dev/e1000/if_em.h +++ sys/dev/e1000/if_em.h @@ -249,6 +249,14 @@ * solve it just using this define. */ #define EM_EIAC 0x000DC +/* + * 82574 only reports 3 MSI-X vectors by default; + * defines assisting with making it report 5 are + * located here. + */ +#define EM_NVM_PCIE_CTRL 0x1B +#define EM_NVM_MSIX_N_MASK (0x7 << EM_NVM_MSIX_N_SHIFT) +#define EM_NVM_MSIX_N_SHIFT 7 /* * Bus dma allocation structure used by @@ -383,7 +391,9 @@ eventhandler_tag vlan_detach; u16 num_vlans; - u16 num_queues; + /* Allow number of tx queues != num of rx_queues */ + u8 num_tx_queues; + u8 num_rx_queues; /* * Transmit rings: Index: sys/dev/e1000/if_em.c =================================================================== --- sys/dev/e1000/if_em.c +++ sys/dev/e1000/if_em.c @@ -32,6 +32,7 @@ ******************************************************************************/ /*$FreeBSD$*/ +#include "opt_em.h" #include "opt_inet.h" #include "opt_inet6.h" @@ -299,6 +300,10 @@ static void em_handle_rx(void *context, int pending); static void em_handle_link(void *context, int pending); +#ifdef EM_MULTIQUEUE +static void em_enable_vectors_82574(struct adapter *); +#endif + static void em_set_sysctl_value(struct adapter *, const char *, const char *, int *, int); static int em_set_flowcntl(SYSCTL_HANDLER_ARGS); @@ -388,6 +393,16 @@ SYSCTL_INT(_hw_em, OID_AUTO, enable_msix, CTLFLAG_RDTUN, &em_enable_msix, 0, "Enable MSI-X interrupts"); +#ifdef EM_MULTIQUEUE +static int em_num_tx_queues = 1; +SYSCTL_INT(_hw_em, OID_AUTO, num_tx_queues, CTLFLAG_RDTUN, &em_num_tx_queues, 0, + "82574 only: Number of tx queues to configure, 0 indicates autoconfigure"); + +static int em_num_rx_queues = 1; +SYSCTL_INT(_hw_em, OID_AUTO, num_rx_queues, CTLFLAG_RDTUN, &em_num_rx_queues, 0, + "82574 only: Number of rx queues to configure, 0 indicates autoconfigure"); +#endif + /* How many packets rxeof tries to clean at a time */ static int em_rx_process_limit = 100; SYSCTL_INT(_hw_em, OID_AUTO, rx_process_limit, CTLFLAG_RDTUN, @@ -458,6 +473,33 @@ return (ENXIO); } +#ifdef EM_MULTIQUEUE +/* + * 82574 only: + * Write a new value to the EEPROM increasing the number of MSIX + * vectors from 3 to 5, for proper multiqueue support. + */ +static void +em_enable_vectors_82574(struct adapter *adapter) +{ + struct e1000_hw *hw = &adapter->hw; + device_t dev = adapter->dev; + u16 edata; + + e1000_read_nvm(hw, EM_NVM_PCIE_CTRL, 1, &edata); + printf("Current cap: %#06x\n", edata); + if (((edata & EM_NVM_MSIX_N_MASK) >> EM_NVM_MSIX_N_SHIFT) != 4) { + device_printf(dev, "Writing to eeprom: increasing " + "reported MSIX vectors from 3 to 5...\n"); + edata &= ~(EM_NVM_MSIX_N_MASK); + edata |= 4 << EM_NVM_MSIX_N_SHIFT; + e1000_write_nvm(hw, EM_NVM_PCIE_CTRL, 1, &edata); + e1000_update_nvm_checksum(hw); + device_printf(dev, "Writing to eeprom: done\n"); + } +} +#endif + /********************************************************************* * Device initialization routine * @@ -550,6 +592,11 @@ goto err_pci; } + /* + * Setup MSI/X or MSI if PCI Express + */ + adapter->msix = em_setup_msix(adapter); + e1000_get_bus_info(hw); /* Set up some sysctls for the tunable interrupt delays */ @@ -876,7 +923,7 @@ if ((if_getflags(ifp) & IFF_UP) && (if_getdrvflags(ifp) & IFF_DRV_RUNNING) && adapter->link_active) { - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { EM_TX_LOCK(txr); #ifdef EM_MULTIQUEUE if (!drbr_empty(ifp, txr->br)) @@ -910,6 +957,8 @@ struct mbuf *next; int err = 0, enq = 0; + EM_TX_LOCK_ASSERT(txr); + if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING || adapter->link_active == 0) { if (m != NULL) @@ -938,7 +987,7 @@ if_inc_counter(ifp, IFCOUNTER_OBYTES, next->m_pkthdr.len); if (next->m_flags & M_MCAST) if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); - if_etherbpfmtap(ifp, next); + ETHER_BPF_MTAP(ifp, next); if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0) break; } @@ -964,7 +1013,14 @@ { struct adapter *adapter = if_getsoftc(ifp); struct tx_ring *txr = adapter->tx_rings; - int error; + int i, error; + + if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) + i = m->m_pkthdr.flowid % adapter->num_tx_queues; + else + i = curcpu % adapter->num_tx_queues; + + txr = &adapter->tx_rings[i]; if (EM_TX_TRYLOCK(txr)) { error = em_mq_start_locked(ifp, txr, m); @@ -985,7 +1041,7 @@ struct tx_ring *txr = adapter->tx_rings; struct mbuf *m; - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { EM_TX_LOCK(txr); while ((m = buf_ring_dequeue_sc(txr->br)) != NULL) m_freem(m); @@ -1033,7 +1089,7 @@ } /* Send a copy of the frame to the BPF listener */ - if_etherbpfmtap(ifp, m_head); + ETHER_BPF_MTAP(ifp, m_head); /* Set timeout in case hardware has problems transmitting. */ txr->watchdog_time = ticks; @@ -1670,7 +1726,7 @@ E1000_WRITE_REG(&adapter->hw, E1000_IMS, EM_MSIX_LINK | E1000_IMS_LSC); if (adapter->link_active) { - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { EM_TX_LOCK(txr); #ifdef EM_MULTIQUEUE if (!drbr_empty(ifp, txr->br)) @@ -2243,7 +2299,7 @@ ** can be done without the lock because its RO ** and the HUNG state will be static if set. */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { if ((txr->queue_status == EM_QUEUE_HUNG) && (adapter->pause_frames == 0)) goto hung; @@ -2341,7 +2397,7 @@ device_printf(dev, "Link is Down\n"); adapter->link_active = 0; /* Link down, disable watchdog */ - for (int i = 0; i < adapter->num_queues; i++, txr++) + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) txr->queue_status = EM_QUEUE_IDLE; if_link_state_change(ifp, LINK_STATE_DOWN); } @@ -2374,7 +2430,7 @@ if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); /* Unarm watchdog timer. */ - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { EM_TX_LOCK(txr); txr->queue_status = EM_QUEUE_IDLE; EM_TX_UNLOCK(txr); @@ -2437,14 +2493,6 @@ rman_get_bushandle(adapter->memory); adapter->hw.hw_addr = (u8 *)&adapter->osdep.mem_bus_space_handle; - /* Default to a single queue */ - adapter->num_queues = 1; - - /* - * Setup MSI/X or MSI if PCI Express - */ - adapter->msix = em_setup_msix(adapter); - adapter->hw.back = &adapter->osdep; return (0); @@ -2525,7 +2573,7 @@ E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xffffffff); /* First set up ring resources */ - for (int i = 0; i < adapter->num_queues; i++, txr++, rxr++) { + for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) { /* RX ring */ rid = vector + 1; @@ -2551,8 +2599,8 @@ TASK_INIT(&rxr->rx_task, 0, em_handle_rx, rxr); rxr->tq = taskqueue_create_fast("em_rxq", M_NOWAIT, taskqueue_thread_enqueue, &rxr->tq); - taskqueue_start_threads(&rxr->tq, 1, PI_NET, "%s rxq", - device_get_nameunit(adapter->dev)); + taskqueue_start_threads(&rxr->tq, 1, PI_NET, "%s rxq (qid %d)", + device_get_nameunit(adapter->dev), i); /* ** Set the bit to enable interrupt ** in E1000_IMS -- bits 20 and 21 @@ -2561,7 +2609,9 @@ */ rxr->ims = 1 << (20 + i); adapter->ivars |= (8 | rxr->msix) << (i * 4); + } + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { /* TX ring */ rid = vector + 1; txr->res = bus_alloc_resource_any(dev, @@ -2585,8 +2635,8 @@ TASK_INIT(&txr->tx_task, 0, em_handle_tx, txr); txr->tq = taskqueue_create_fast("em_txq", M_NOWAIT, taskqueue_thread_enqueue, &txr->tq); - taskqueue_start_threads(&txr->tq, 1, PI_NET, "%s txq", - device_get_nameunit(adapter->dev)); + taskqueue_start_threads(&txr->tq, 1, PI_NET, "%s txq (qid %d)", + device_get_nameunit(adapter->dev), i); /* ** Set the bit to enable interrupt ** in E1000_IMS -- bits 22 and 23 @@ -2638,11 +2688,10 @@ /* ** Release all the queue interrupt resources: */ - for (int i = 0; i < adapter->num_queues; i++) { + for (int i = 0; i < adapter->num_tx_queues; i++) { txr = &adapter->tx_rings[i]; - rxr = &adapter->rx_rings[i]; /* an early abort? */ - if ((txr == NULL) || (rxr == NULL)) + if (txr == NULL) break; rid = txr->msix +1; if (txr->tag != NULL) { @@ -2652,6 +2701,13 @@ if (txr->res != NULL) bus_release_resource(dev, SYS_RES_IRQ, rid, txr->res); + } + + for (int i = 0; i < adapter->num_tx_queues; i++) { + rxr = &adapter->rx_rings[i]; + /* an early abort? */ + if (rxr == NULL) + break; rid = rxr->msix +1; if (rxr->tag != NULL) { bus_teardown_intr(dev, rxr->res, rxr->tag); @@ -2701,14 +2757,21 @@ device_t dev = adapter->dev; int val; + /* Nearly always going to use one queue */ + adapter->num_rx_queues = 1; + adapter->num_tx_queues = 1; + /* - ** Setup MSI/X for Hartwell: tests have shown - ** use of two queues to be unstable, and to - ** provide no great gain anyway, so we simply - ** seperate the interrupts and use a single queue. + ** Try using MSI-X for Hartwell adapters */ if ((adapter->hw.mac.type == e1000_82574) && (em_enable_msix == TRUE)) { +#ifdef EM_MULTIQUEUE + adapter->num_tx_queues = (em_num_tx_queues == 1) ? 1 : 2; + adapter->num_rx_queues = (em_num_rx_queues == 1) ? 1 : 2; + if (adapter->num_rx_queues > 1 || adapter->num_tx_queues > 1) + em_enable_vectors_82574(adapter); +#endif /* Map the MSIX BAR */ int rid = PCIR_BAR(EM_MSIX_BAR); adapter->msix_mem = bus_alloc_resource_any(dev, @@ -2720,16 +2783,35 @@ goto msi; } val = pci_msix_count(dev); - /* We only need/want 3 vectors */ - if (val >= 3) - val = 3; - else { - device_printf(adapter->dev, - "MSIX: insufficient vectors, using MSI\n"); - goto msi; + +#ifdef EM_MULTIQUEUE + /* We need 5 vectors in the multiqueue case */ + if (adapter->num_rx_queues > 1 || adapter->num_tx_queues > 1) { + if (val >= 5) + val = 5; + else { + adapter->num_tx_queues = 1; + adapter->num_rx_queues = 1; + device_printf(adapter->dev, + "Insufficient MSIX vectors for >1 queue, " + "using single queue...\n"); + goto msix_one; + } + } else { +msix_one: +#endif + if (val >= 3) + val = 3; + else { + device_printf(adapter->dev, + "Insufficient MSIX vectors, using MSI\n"); + goto msi; + } +#ifdef EM_MULTIQUEUE } +#endif - if ((pci_alloc_msix(dev, &val) == 0) && (val == 3)) { + if ((pci_alloc_msix(dev, &val) == 0)) { device_printf(adapter->dev, "Using MSIX interrupts " "with %d vectors\n", val); @@ -2750,7 +2832,7 @@ } val = 1; if (pci_alloc_msi(dev, &val) == 0) { - device_printf(adapter->dev,"Using an MSI interrupt\n"); + device_printf(adapter->dev, "Using an MSI interrupt\n"); return (val); } /* Should only happen due to manual configuration */ @@ -3130,7 +3212,7 @@ /* Allocate the TX ring struct memory */ if (!(adapter->tx_rings = (struct tx_ring *) malloc(sizeof(struct tx_ring) * - adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + adapter->num_tx_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate TX ring memory\n"); error = ENOMEM; goto fail; @@ -3139,7 +3221,7 @@ /* Now allocate the RX */ if (!(adapter->rx_rings = (struct rx_ring *) malloc(sizeof(struct rx_ring) * - adapter->num_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { + adapter->num_rx_queues, M_DEVBUF, M_NOWAIT | M_ZERO))) { device_printf(dev, "Unable to allocate RX ring memory\n"); error = ENOMEM; goto rx_fail; @@ -3152,7 +3234,7 @@ * possibility that things fail midcourse and we need to * undo memory gracefully */ - for (int i = 0; i < adapter->num_queues; i++, txconf++) { + for (int i = 0; i < adapter->num_tx_queues; i++, txconf++) { /* Set up some basics */ txr = &adapter->tx_rings[i]; txr->adapter = adapter; @@ -3191,7 +3273,7 @@ */ rsize = roundup2(adapter->num_rx_desc * sizeof(struct e1000_rx_desc), EM_DBA_ALIGN); - for (int i = 0; i < adapter->num_queues; i++, rxconf++) { + for (int i = 0; i < adapter->num_rx_queues; i++, rxconf++) { rxr = &adapter->rx_rings[i]; rxr->adapter = adapter; rxr->me = i; @@ -3379,7 +3461,7 @@ { struct tx_ring *txr = adapter->tx_rings; - for (int i = 0; i < adapter->num_queues; i++, txr++) + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) em_setup_transmit_ring(txr); return; @@ -3399,7 +3481,7 @@ INIT_DEBUGOUT("em_initialize_transmit_unit: begin"); - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { u64 bus_addr = txr->txdma.dma_paddr; /* Base and Len of TX Ring */ E1000_WRITE_REG(hw, E1000_TDLEN(i), @@ -3487,7 +3569,7 @@ { struct tx_ring *txr = adapter->tx_rings; - for (int i = 0; i < adapter->num_queues; i++, txr++) { + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { EM_TX_LOCK(txr); em_free_transmit_buffers(txr); em_dma_free(adapter, &txr->txdma); @@ -4137,7 +4219,7 @@ struct rx_ring *rxr = adapter->rx_rings; int q; - for (q = 0; q < adapter->num_queues; q++, rxr++) + for (q = 0; q < adapter->num_rx_queues; q++, rxr++) if (em_setup_receive_ring(rxr)) goto fail; @@ -4178,7 +4260,7 @@ { struct rx_ring *rxr = adapter->rx_rings; - for (int i = 0; i < adapter->num_queues; i++, rxr++) { + for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) { em_free_receive_buffers(rxr); /* Free the ring memory as well */ em_dma_free(adapter, &rxr->rxdma); @@ -4278,12 +4360,54 @@ } rxcsum = E1000_READ_REG(hw, E1000_RXCSUM); - if (if_getcapenable(ifp) & IFCAP_RXCSUM) + if (if_getcapenable(ifp) & IFCAP_RXCSUM) { +#ifdef EM_MULTIQUEUE + rxcsum |= E1000_RXCSUM_TUOFL | + E1000_RXCSUM_IPOFL | + E1000_RXCSUM_PCSD; +#else rxcsum |= E1000_RXCSUM_TUOFL; - else +#endif + } else rxcsum &= ~E1000_RXCSUM_TUOFL; + E1000_WRITE_REG(hw, E1000_RXCSUM, rxcsum); +#ifdef EM_MULTIQUEUE + if (adapter->num_rx_queues > 1) { + uint32_t rss_key[10]; + uint32_t reta; + int i; + + /* + * Configure RSS key + */ + arc4rand(rss_key, sizeof(rss_key), 0); + for (i = 0; i < 10; ++i) + E1000_WRITE_REG_ARRAY(hw,E1000_RSSRK(0), i, rss_key[i]); + + /* + * Configure RSS redirect table in following fashion: + * (hash & ring_cnt_mask) == rdr_table[(hash & rdr_table_mask)] + */ + reta = 0; + for (i = 0; i < 4; ++i) { + uint32_t q; + q = (i % 2) << 7; + reta |= q << (8 * i); + } + for (i = 0; i < 32; ++i) + E1000_WRITE_REG(hw, E1000_RETA(i), reta); + + E1000_WRITE_REG(hw, E1000_MRQC, E1000_MRQC_RSS_ENABLE_2Q | + E1000_MRQC_RSS_FIELD_IPV4_TCP | + E1000_MRQC_RSS_FIELD_IPV4 | + E1000_MRQC_RSS_FIELD_IPV6_TCP_EX | + E1000_MRQC_RSS_FIELD_IPV6_EX | + E1000_MRQC_RSS_FIELD_IPV6 | + E1000_MRQC_RSS_FIELD_IPV6_TCP); + } +#endif /* ** XXX TEMPORARY WORKAROUND: on some systems with 82573 ** long latencies are observed, like Lenovo X60. This @@ -4294,7 +4418,7 @@ if (hw->mac.type == e1000_82573) E1000_WRITE_REG(hw, E1000_RDTR, 0x20); - for (int i = 0; i < adapter->num_queues; i++, rxr++) { + for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) { /* Setup the Base and Length of the Rx Descriptor Ring */ u32 rdt = adapter->num_rx_desc - 1; /* default */ @@ -4317,7 +4441,6 @@ #endif /* DEV_NETMAP */ E1000_WRITE_REG(hw, E1000_RDT(i), rdt); } - /* Set PTHRESH for improved jumbo performance */ if (((adapter->hw.mac.type == e1000_ich9lan) || (adapter->hw.mac.type == e1000_pch2lan) || @@ -5297,10 +5420,10 @@ CTLFLAG_RD, &adapter->hw.fc.low_water, 0, "Flow Control Low Watermark"); - for (int i = 0; i < adapter->num_queues; i++, rxr++, txr++) { - snprintf(namebuf, QUEUE_NAME_LEN, "queue%d", i); + for (int i = 0; i < adapter->num_tx_queues; i++, txr++) { + snprintf(namebuf, QUEUE_NAME_LEN, "queue_tx_%d", i); queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, - CTLFLAG_RD, NULL, "Queue Name"); + CTLFLAG_RD, NULL, "TX Queue Name"); queue_list = SYSCTL_CHILDREN(queue_node); SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "txd_head", @@ -5319,7 +5442,13 @@ SYSCTL_ADD_ULONG(ctx, queue_list, OID_AUTO, "no_desc_avail", CTLFLAG_RD, &txr->no_desc_avail, "Queue No Descriptor Available"); - + } + for (int i = 0; i < adapter->num_rx_queues; i++, rxr++) { + snprintf(namebuf, QUEUE_NAME_LEN, "queue_rx_%d", i); + queue_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, namebuf, + CTLFLAG_RD, NULL, "RX Queue Name"); + queue_list = SYSCTL_CHILDREN(queue_node); + SYSCTL_ADD_PROC(ctx, queue_list, OID_AUTO, "rxd_head", CTLTYPE_UINT | CTLFLAG_RD, adapter, E1000_RDH(rxr->me), Index: sys/dev/netmap/if_em_netmap.h =================================================================== --- sys/dev/netmap/if_em_netmap.h +++ sys/dev/netmap/if_em_netmap.h @@ -48,9 +48,11 @@ struct tx_ring *txr = adapter->tx_rings; struct rx_ring *rxr = adapter->rx_rings; - for (i = 0; i < adapter->num_queues; i++, txr++, rxr++) { + for (i = 0; i < adapter->num_tx_queues; i++, txr++) { taskqueue_block(txr->tq); taskqueue_drain(txr->tq, &txr->tx_task); + } + for (i = 0; i < adapter->num_rx_queues; i++, rxr++) { taskqueue_block(rxr->tq); taskqueue_drain(rxr->tq, &rxr->rx_task); } @@ -70,8 +72,10 @@ struct rx_ring *rxr = adapter->rx_rings; int i; - for (i = 0; i < adapter->num_queues; i++) { + for (i = 0; i < adapter->num_tx_queues; i++) { taskqueue_unblock(txr->tq); + } + for (i = 0; i < adapter->num_rx_queues; i++) { taskqueue_unblock(rxr->tq); } } else { /* legacy */ @@ -327,7 +331,8 @@ na.nm_txsync = em_netmap_txsync; na.nm_rxsync = em_netmap_rxsync; na.nm_register = em_netmap_reg; - na.num_tx_rings = na.num_rx_rings = adapter->num_queues; + na.num_tx_rings = adapter->num_tx_queues; + na.num_rx_rings = adapter->num_rx_queues; netmap_attach(&na); }