common/sfc_efx/base: move EvQ init/fini wrappers to generic
EvQ init/fini MCDI is similar on Riverhead and these functions should be reused to implement EvQ creation and destruction on Riverhead. Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com> Reviewed-by: Andy Moreton <amoreton@xilinx.com> Reviewed-by: Vijay Kumar Srivastava <vsrivast@xilinx.com>
This commit is contained in:
parent
90ff7b9bf4
commit
8527058133
@ -100,310 +100,6 @@ efx_mcdi_set_evq_tmr(
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static __checkReturn efx_rc_t
|
||||
efx_mcdi_init_evq(
|
||||
__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,
|
||||
__in uint32_t flags,
|
||||
__in boolean_t low_latency)
|
||||
{
|
||||
efx_mcdi_req_t req;
|
||||
EFX_MCDI_DECLARE_BUF(payload,
|
||||
MC_CMD_INIT_EVQ_IN_LEN(EF10_EVQ_MAXNBUFS),
|
||||
MC_CMD_INIT_EVQ_OUT_LEN);
|
||||
efx_qword_t *dma_addr;
|
||||
uint64_t addr;
|
||||
int npages;
|
||||
int i;
|
||||
boolean_t interrupting;
|
||||
int ev_cut_through;
|
||||
efx_rc_t rc;
|
||||
|
||||
npages = efx_evq_nbufs(enp, nevs);
|
||||
if (npages > EF10_EVQ_MAXNBUFS) {
|
||||
rc = EINVAL;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
req.emr_cmd = MC_CMD_INIT_EVQ;
|
||||
req.emr_in_buf = payload;
|
||||
req.emr_in_length = MC_CMD_INIT_EVQ_IN_LEN(npages);
|
||||
req.emr_out_buf = payload;
|
||||
req.emr_out_length = MC_CMD_INIT_EVQ_OUT_LEN;
|
||||
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_SIZE, nevs);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_INSTANCE, instance);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_IRQ_NUM, irq);
|
||||
|
||||
interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
|
||||
EFX_EVQ_FLAGS_NOTIFY_INTERRUPT);
|
||||
|
||||
/*
|
||||
* 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 event cut
|
||||
* through if we want low latency operation.
|
||||
*/
|
||||
switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) {
|
||||
case EFX_EVQ_FLAGS_TYPE_AUTO:
|
||||
ev_cut_through = low_latency ? 1 : 0;
|
||||
break;
|
||||
case EFX_EVQ_FLAGS_TYPE_THROUGHPUT:
|
||||
ev_cut_through = 0;
|
||||
break;
|
||||
case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY:
|
||||
ev_cut_through = 1;
|
||||
break;
|
||||
default:
|
||||
rc = EINVAL;
|
||||
goto fail2;
|
||||
}
|
||||
MCDI_IN_POPULATE_DWORD_6(req, INIT_EVQ_IN_FLAGS,
|
||||
INIT_EVQ_IN_FLAG_INTERRUPTING, interrupting,
|
||||
INIT_EVQ_IN_FLAG_RPTR_DOS, 0,
|
||||
INIT_EVQ_IN_FLAG_INT_ARMD, 0,
|
||||
INIT_EVQ_IN_FLAG_CUT_THRU, ev_cut_through,
|
||||
INIT_EVQ_IN_FLAG_RX_MERGE, 1,
|
||||
INIT_EVQ_IN_FLAG_TX_MERGE, 1);
|
||||
|
||||
/* If the value is zero then disable the timer */
|
||||
if (us == 0) {
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE,
|
||||
MC_CMD_INIT_EVQ_IN_TMR_MODE_DIS);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, 0);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, 0);
|
||||
} else {
|
||||
unsigned int ticks;
|
||||
|
||||
if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0)
|
||||
goto fail3;
|
||||
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE,
|
||||
MC_CMD_INIT_EVQ_IN_TMR_INT_HLDOFF);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, ticks);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, ticks);
|
||||
}
|
||||
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_MODE,
|
||||
MC_CMD_INIT_EVQ_IN_COUNT_MODE_DIS);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_THRSHLD, 0);
|
||||
|
||||
dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_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 fail4;
|
||||
}
|
||||
|
||||
if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) {
|
||||
rc = EMSGSIZE;
|
||||
goto fail5;
|
||||
}
|
||||
|
||||
/* NOTE: ignore the returned IRQ param as firmware does not set it. */
|
||||
|
||||
return (0);
|
||||
|
||||
fail5:
|
||||
EFSYS_PROBE(fail5);
|
||||
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_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,
|
||||
__in uint32_t flags)
|
||||
{
|
||||
efx_mcdi_req_t req;
|
||||
EFX_MCDI_DECLARE_BUF(payload,
|
||||
MC_CMD_INIT_EVQ_V2_IN_LEN(EF10_EVQ_MAXNBUFS),
|
||||
MC_CMD_INIT_EVQ_V2_OUT_LEN);
|
||||
boolean_t interrupting;
|
||||
unsigned int evq_type;
|
||||
efx_qword_t *dma_addr;
|
||||
uint64_t addr;
|
||||
int npages;
|
||||
int i;
|
||||
efx_rc_t rc;
|
||||
|
||||
npages = efx_evq_nbufs(enp, nevs);
|
||||
if (npages > EF10_EVQ_MAXNBUFS) {
|
||||
rc = EINVAL;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
|
||||
EFX_EVQ_FLAGS_NOTIFY_INTERRUPT);
|
||||
|
||||
switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) {
|
||||
case EFX_EVQ_FLAGS_TYPE_AUTO:
|
||||
evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_AUTO;
|
||||
break;
|
||||
case EFX_EVQ_FLAGS_TYPE_THROUGHPUT:
|
||||
evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_THROUGHPUT;
|
||||
break;
|
||||
case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY:
|
||||
evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_LOW_LATENCY;
|
||||
break;
|
||||
default:
|
||||
rc = EINVAL;
|
||||
goto fail2;
|
||||
}
|
||||
MCDI_IN_POPULATE_DWORD_4(req, INIT_EVQ_V2_IN_FLAGS,
|
||||
INIT_EVQ_V2_IN_FLAG_INTERRUPTING, interrupting,
|
||||
INIT_EVQ_V2_IN_FLAG_RPTR_DOS, 0,
|
||||
INIT_EVQ_V2_IN_FLAG_INT_ARMD, 0,
|
||||
INIT_EVQ_V2_IN_FLAG_TYPE, evq_type);
|
||||
|
||||
/* 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 fail3;
|
||||
|
||||
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 fail4;
|
||||
}
|
||||
|
||||
if (req.emr_out_length_used < MC_CMD_INIT_EVQ_V2_OUT_LEN) {
|
||||
rc = EMSGSIZE;
|
||||
goto fail5;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
fail5:
|
||||
EFSYS_PROBE(fail5);
|
||||
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,
|
||||
__in uint32_t instance)
|
||||
{
|
||||
efx_mcdi_req_t req;
|
||||
EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_EVQ_IN_LEN,
|
||||
MC_CMD_FINI_EVQ_OUT_LEN);
|
||||
efx_rc_t rc;
|
||||
|
||||
req.emr_cmd = MC_CMD_FINI_EVQ;
|
||||
req.emr_in_buf = payload;
|
||||
req.emr_in_length = MC_CMD_FINI_EVQ_IN_LEN;
|
||||
req.emr_out_buf = payload;
|
||||
req.emr_out_length = MC_CMD_FINI_EVQ_OUT_LEN;
|
||||
|
||||
MCDI_IN_SET_DWORD(req, FINI_EVQ_IN_INSTANCE, instance);
|
||||
|
||||
efx_mcdi_execute_quiet(enp, &req);
|
||||
|
||||
if (req.emr_rc != 0) {
|
||||
rc = req.emr_rc;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
fail1:
|
||||
/*
|
||||
* EALREADY is not an error, but indicates that the MC has rebooted and
|
||||
* that the EVQ has already been destroyed.
|
||||
*/
|
||||
if (rc != EALREADY)
|
||||
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
__checkReturn efx_rc_t
|
||||
ef10_ev_init(
|
||||
|
@ -1408,6 +1408,39 @@ efx_mcdi_get_workarounds(
|
||||
__out_opt uint32_t *implementedp,
|
||||
__out_opt uint32_t *enabledp);
|
||||
|
||||
#if EFX_OPTS_EF10()
|
||||
|
||||
LIBEFX_INTERNAL
|
||||
extern __checkReturn efx_rc_t
|
||||
efx_mcdi_init_evq(
|
||||
__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,
|
||||
__in uint32_t flags,
|
||||
__in boolean_t low_latency);
|
||||
|
||||
LIBEFX_INTERNAL
|
||||
extern __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,
|
||||
__in uint32_t flags);
|
||||
|
||||
LIBEFX_INTERNAL
|
||||
extern __checkReturn efx_rc_t
|
||||
efx_mcdi_fini_evq(
|
||||
__in efx_nic_t *enp,
|
||||
__in uint32_t instance);
|
||||
|
||||
#endif /* EFX_OPTS_EF10() */
|
||||
|
||||
#endif /* EFSYS_OPT_MCDI */
|
||||
|
||||
#if EFSYS_OPT_MAC_STATS
|
||||
|
@ -2443,4 +2443,310 @@ efx_mcdi_phy_module_get_info(
|
||||
return (rc);
|
||||
}
|
||||
|
||||
#if EFX_OPTS_EF10()
|
||||
|
||||
__checkReturn efx_rc_t
|
||||
efx_mcdi_init_evq(
|
||||
__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,
|
||||
__in uint32_t flags,
|
||||
__in boolean_t low_latency)
|
||||
{
|
||||
efx_mcdi_req_t req;
|
||||
EFX_MCDI_DECLARE_BUF(payload,
|
||||
MC_CMD_INIT_EVQ_IN_LEN(EF10_EVQ_MAXNBUFS),
|
||||
MC_CMD_INIT_EVQ_OUT_LEN);
|
||||
efx_qword_t *dma_addr;
|
||||
uint64_t addr;
|
||||
int npages;
|
||||
int i;
|
||||
boolean_t interrupting;
|
||||
int ev_cut_through;
|
||||
efx_rc_t rc;
|
||||
|
||||
npages = efx_evq_nbufs(enp, nevs);
|
||||
if (npages > EF10_EVQ_MAXNBUFS) {
|
||||
rc = EINVAL;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
req.emr_cmd = MC_CMD_INIT_EVQ;
|
||||
req.emr_in_buf = payload;
|
||||
req.emr_in_length = MC_CMD_INIT_EVQ_IN_LEN(npages);
|
||||
req.emr_out_buf = payload;
|
||||
req.emr_out_length = MC_CMD_INIT_EVQ_OUT_LEN;
|
||||
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_SIZE, nevs);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_INSTANCE, instance);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_IRQ_NUM, irq);
|
||||
|
||||
interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
|
||||
EFX_EVQ_FLAGS_NOTIFY_INTERRUPT);
|
||||
|
||||
/*
|
||||
* 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 event cut
|
||||
* through if we want low latency operation.
|
||||
*/
|
||||
switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) {
|
||||
case EFX_EVQ_FLAGS_TYPE_AUTO:
|
||||
ev_cut_through = low_latency ? 1 : 0;
|
||||
break;
|
||||
case EFX_EVQ_FLAGS_TYPE_THROUGHPUT:
|
||||
ev_cut_through = 0;
|
||||
break;
|
||||
case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY:
|
||||
ev_cut_through = 1;
|
||||
break;
|
||||
default:
|
||||
rc = EINVAL;
|
||||
goto fail2;
|
||||
}
|
||||
MCDI_IN_POPULATE_DWORD_6(req, INIT_EVQ_IN_FLAGS,
|
||||
INIT_EVQ_IN_FLAG_INTERRUPTING, interrupting,
|
||||
INIT_EVQ_IN_FLAG_RPTR_DOS, 0,
|
||||
INIT_EVQ_IN_FLAG_INT_ARMD, 0,
|
||||
INIT_EVQ_IN_FLAG_CUT_THRU, ev_cut_through,
|
||||
INIT_EVQ_IN_FLAG_RX_MERGE, 1,
|
||||
INIT_EVQ_IN_FLAG_TX_MERGE, 1);
|
||||
|
||||
/* If the value is zero then disable the timer */
|
||||
if (us == 0) {
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE,
|
||||
MC_CMD_INIT_EVQ_IN_TMR_MODE_DIS);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, 0);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, 0);
|
||||
} else {
|
||||
unsigned int ticks;
|
||||
|
||||
if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0)
|
||||
goto fail3;
|
||||
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_MODE,
|
||||
MC_CMD_INIT_EVQ_IN_TMR_INT_HLDOFF);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_LOAD, ticks);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_TMR_RELOAD, ticks);
|
||||
}
|
||||
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_MODE,
|
||||
MC_CMD_INIT_EVQ_IN_COUNT_MODE_DIS);
|
||||
MCDI_IN_SET_DWORD(req, INIT_EVQ_IN_COUNT_THRSHLD, 0);
|
||||
|
||||
dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_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 fail4;
|
||||
}
|
||||
|
||||
if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) {
|
||||
rc = EMSGSIZE;
|
||||
goto fail5;
|
||||
}
|
||||
|
||||
/* NOTE: ignore the returned IRQ param as firmware does not set it. */
|
||||
|
||||
return (0);
|
||||
|
||||
fail5:
|
||||
EFSYS_PROBE(fail5);
|
||||
fail4:
|
||||
EFSYS_PROBE(fail4);
|
||||
fail3:
|
||||
EFSYS_PROBE(fail3);
|
||||
fail2:
|
||||
EFSYS_PROBE(fail2);
|
||||
fail1:
|
||||
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
__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,
|
||||
__in uint32_t flags)
|
||||
{
|
||||
efx_mcdi_req_t req;
|
||||
EFX_MCDI_DECLARE_BUF(payload,
|
||||
MC_CMD_INIT_EVQ_V2_IN_LEN(EF10_EVQ_MAXNBUFS),
|
||||
MC_CMD_INIT_EVQ_V2_OUT_LEN);
|
||||
boolean_t interrupting;
|
||||
unsigned int evq_type;
|
||||
efx_qword_t *dma_addr;
|
||||
uint64_t addr;
|
||||
int npages;
|
||||
int i;
|
||||
efx_rc_t rc;
|
||||
|
||||
npages = efx_evq_nbufs(enp, nevs);
|
||||
if (npages > EF10_EVQ_MAXNBUFS) {
|
||||
rc = EINVAL;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) ==
|
||||
EFX_EVQ_FLAGS_NOTIFY_INTERRUPT);
|
||||
|
||||
switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) {
|
||||
case EFX_EVQ_FLAGS_TYPE_AUTO:
|
||||
evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_AUTO;
|
||||
break;
|
||||
case EFX_EVQ_FLAGS_TYPE_THROUGHPUT:
|
||||
evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_THROUGHPUT;
|
||||
break;
|
||||
case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY:
|
||||
evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_LOW_LATENCY;
|
||||
break;
|
||||
default:
|
||||
rc = EINVAL;
|
||||
goto fail2;
|
||||
}
|
||||
MCDI_IN_POPULATE_DWORD_4(req, INIT_EVQ_V2_IN_FLAGS,
|
||||
INIT_EVQ_V2_IN_FLAG_INTERRUPTING, interrupting,
|
||||
INIT_EVQ_V2_IN_FLAG_RPTR_DOS, 0,
|
||||
INIT_EVQ_V2_IN_FLAG_INT_ARMD, 0,
|
||||
INIT_EVQ_V2_IN_FLAG_TYPE, evq_type);
|
||||
|
||||
/* 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 fail3;
|
||||
|
||||
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 fail4;
|
||||
}
|
||||
|
||||
if (req.emr_out_length_used < MC_CMD_INIT_EVQ_V2_OUT_LEN) {
|
||||
rc = EMSGSIZE;
|
||||
goto fail5;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
fail5:
|
||||
EFSYS_PROBE(fail5);
|
||||
fail4:
|
||||
EFSYS_PROBE(fail4);
|
||||
fail3:
|
||||
EFSYS_PROBE(fail3);
|
||||
fail2:
|
||||
EFSYS_PROBE(fail2);
|
||||
fail1:
|
||||
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
__checkReturn efx_rc_t
|
||||
efx_mcdi_fini_evq(
|
||||
__in efx_nic_t *enp,
|
||||
__in uint32_t instance)
|
||||
{
|
||||
efx_mcdi_req_t req;
|
||||
EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_EVQ_IN_LEN,
|
||||
MC_CMD_FINI_EVQ_OUT_LEN);
|
||||
efx_rc_t rc;
|
||||
|
||||
req.emr_cmd = MC_CMD_FINI_EVQ;
|
||||
req.emr_in_buf = payload;
|
||||
req.emr_in_length = MC_CMD_FINI_EVQ_IN_LEN;
|
||||
req.emr_out_buf = payload;
|
||||
req.emr_out_length = MC_CMD_FINI_EVQ_OUT_LEN;
|
||||
|
||||
MCDI_IN_SET_DWORD(req, FINI_EVQ_IN_INSTANCE, instance);
|
||||
|
||||
efx_mcdi_execute_quiet(enp, &req);
|
||||
|
||||
if (req.emr_rc != 0) {
|
||||
rc = req.emr_rc;
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
fail1:
|
||||
/*
|
||||
* EALREADY is not an error, but indicates that the MC has rebooted and
|
||||
* that the EVQ has already been destroyed.
|
||||
*/
|
||||
if (rc != EALREADY)
|
||||
EFSYS_PROBE1(fail1, efx_rc_t, rc);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
#endif /* EFX_OPTS_EF10() */
|
||||
|
||||
#endif /* EFSYS_OPT_MCDI */
|
||||
|
Loading…
Reference in New Issue
Block a user