Index: head/sys/dev/sfxge/common/ef10_ev.c =================================================================== --- head/sys/dev/sfxge/common/ef10_ev.c +++ head/sys/dev/sfxge/common/ef10_ev.c @@ -139,7 +139,8 @@ __in efsys_mem_t *esmp, __in size_t nevs, __in uint32_t irq, - __in uint32_t us) + __in uint32_t us, + __in boolean_t low_latency) { efx_mcdi_req_t req; uint8_t payload[ @@ -149,7 +150,7 @@ uint64_t addr; int npages; int i; - int supports_rx_batching; + int ev_cut_through; efx_rc_t rc; npages = EFX_EVQ_NBUFS(nevs); @@ -170,21 +171,19 @@ MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_IRQ_NUM, irq); /* - * On Huntington RX and TX event batching can only be requested - * together (even if the datapath firmware doesn't actually support RX - * batching). - * Cut through is incompatible with RX batching and so enabling cut - * through disables RX batching (but it does not affect TX batching). + * On Huntington RX and TX event batching can only be requested together + * (even if the datapath firmware doesn't actually support RX + * batching). If event cut through is enabled no RX batching will occur. * - * So always enable RX and TX event batching, and enable cut through - * if RX event batching isn't supported (i.e. on low latency firmware). + * So always enable RX and TX event batching, and enable event cut + * through if we want low latency operation. */ - supports_rx_batching = enp->en_nic_cfg.enc_rx_batching_enabled ? 1 : 0; + ev_cut_through = low_latency ? 1 : 0; MCDI_IN_POPULATE_DWORD_6(req, INIT_EVQ_IN_FLAGS, INIT_EVQ_IN_FLAG_INTERRUPTING, 1, INIT_EVQ_IN_FLAG_RPTR_DOS, 0, INIT_EVQ_IN_FLAG_INT_ARMD, 0, - INIT_EVQ_IN_FLAG_CUT_THRU, !supports_rx_batching, + INIT_EVQ_IN_FLAG_CUT_THRU, ev_cut_through, INIT_EVQ_IN_FLAG_RX_MERGE, 1, INIT_EVQ_IN_FLAG_TX_MERGE, 1); @@ -250,6 +249,114 @@ return (rc); } + +static __checkReturn efx_rc_t +efx_mcdi_init_evq_v2( + __in efx_nic_t *enp, + __in unsigned int instance, + __in efsys_mem_t *esmp, + __in size_t nevs, + __in uint32_t irq, + __in uint32_t us) +{ + efx_mcdi_req_t req; + uint8_t payload[ + MAX(MC_CMD_INIT_EVQ_V2_IN_LEN(EFX_EVQ_NBUFS(EFX_EVQ_MAXNEVS)), + MC_CMD_INIT_EVQ_V2_OUT_LEN)]; + efx_qword_t *dma_addr; + uint64_t addr; + int npages; + int i; + efx_rc_t rc; + + npages = EFX_EVQ_NBUFS(nevs); + if (MC_CMD_INIT_EVQ_V2_IN_LEN(npages) > MC_CMD_INIT_EVQ_V2_IN_LENMAX) { + rc = EINVAL; + goto fail1; + } + + (void) memset(payload, 0, sizeof (payload)); + req.emr_cmd = MC_CMD_INIT_EVQ; + req.emr_in_buf = payload; + req.emr_in_length = MC_CMD_INIT_EVQ_V2_IN_LEN(npages); + req.emr_out_buf = payload; + req.emr_out_length = MC_CMD_INIT_EVQ_V2_OUT_LEN; + + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_SIZE, nevs); + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_INSTANCE, instance); + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_IRQ_NUM, irq); + + MCDI_IN_POPULATE_DWORD_4(req, INIT_EVQ_V2_IN_FLAGS, + INIT_EVQ_V2_IN_FLAG_INTERRUPTING, 1, + INIT_EVQ_V2_IN_FLAG_RPTR_DOS, 0, + INIT_EVQ_V2_IN_FLAG_INT_ARMD, 0, + INIT_EVQ_V2_IN_FLAG_TYPE, MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_AUTO); + + /* If the value is zero then disable the timer */ + if (us == 0) { + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE, + MC_CMD_INIT_EVQ_V2_IN_TMR_MODE_DIS); + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, 0); + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, 0); + } else { + unsigned int ticks; + + if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0) + goto fail2; + + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE, + MC_CMD_INIT_EVQ_V2_IN_TMR_INT_HLDOFF); + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, ticks); + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, ticks); + } + + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_MODE, + MC_CMD_INIT_EVQ_V2_IN_COUNT_MODE_DIS); + MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_THRSHLD, 0); + + dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_V2_IN_DMA_ADDR); + addr = EFSYS_MEM_ADDR(esmp); + + for (i = 0; i < npages; i++) { + EFX_POPULATE_QWORD_2(*dma_addr, + EFX_DWORD_1, (uint32_t)(addr >> 32), + EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); + + dma_addr++; + addr += EFX_BUF_SIZE; + } + + efx_mcdi_execute(enp, &req); + + if (req.emr_rc != 0) { + rc = req.emr_rc; + goto fail3; + } + + if (req.emr_out_length_used < MC_CMD_INIT_EVQ_V2_OUT_LEN) { + rc = EMSGSIZE; + goto fail4; + } + + /* NOTE: ignore the returned IRQ param as firmware does not set it. */ + + EFSYS_PROBE1(mcdi_evq_flags, uint32_t, + MCDI_OUT_DWORD(req, INIT_EVQ_V2_OUT_FLAGS)); + + return (0); + +fail4: + EFSYS_PROBE(fail4); +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, efx_rc_t, rc); + + return (rc); +} + static __checkReturn efx_rc_t efx_mcdi_fini_evq( __in efx_nic_t *enp, @@ -348,11 +455,41 @@ * Interrupts may be raised for events immediately after the queue is * created. See bug58606. */ - if ((rc = efx_mcdi_init_evq(enp, index, esmp, n, irq, us)) != 0) - goto fail4; + + if (encp->enc_init_evq_v2_supported) { + /* + * On Medford the low latency license is required to enable RX + * and event cut through and to disable RX batching. We let the + * firmware decide the settings to use. If the adapter has a low + * latency license, it will choose the best settings for low + * latency, otherwise it choose the best settings for + * throughput. + */ + rc = efx_mcdi_init_evq_v2(enp, index, esmp, n, irq, us); + if (rc != 0) + goto fail4; + } else { + /* + * On Huntington we need to specify the settings to use. We + * favour latency if the adapter is running low-latency firmware + * and throughput otherwise, and assume not support RX batching + * implies the adapter is running low-latency firmware. (This + * is how it's been done since Huntington GA. It doesn't make + * much sense with hindsight as the 'low-latency' firmware + * variant is also best for throughput, and does now support RX + * batching). + */ + boolean_t low_latency = encp->enc_rx_batching_enabled ? 0 : 1; + rc = efx_mcdi_init_evq(enp, index, esmp, n, irq, us, + low_latency); + if (rc != 0) + goto fail5; + } return (0); +fail5: + EFSYS_PROBE(fail5); fail4: EFSYS_PROBE(fail4); fail3: Index: head/sys/dev/sfxge/common/ef10_nic.c =================================================================== --- head/sys/dev/sfxge/common/ef10_nic.c +++ head/sys/dev/sfxge/common/ef10_nic.c @@ -1025,6 +1025,13 @@ encp->enc_enhanced_set_mac_supported = CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE; + /* + * Check if firmware supports version 2 of MC_CMD_INIT_EVQ, which allows + * us to let the firmware choose the settings to use on an EVQ. + */ + encp->enc_init_evq_v2_supported = + CAP_FLAG2(flags2, INIT_EVQ_V2) ? B_TRUE : B_FALSE; + #undef CAP_FLAG #undef CAP_FLAG2 Index: head/sys/dev/sfxge/common/efx.h =================================================================== --- head/sys/dev/sfxge/common/efx.h +++ head/sys/dev/sfxge/common/efx.h @@ -1148,6 +1148,7 @@ boolean_t enc_rx_disable_scatter_supported; boolean_t enc_allow_set_mac_with_installed_filters; boolean_t enc_enhanced_set_mac_supported; + boolean_t enc_init_evq_v2_supported; /* External port identifier */ uint8_t enc_external_port; uint32_t enc_mcdi_max_payload_length;