common/sfc_efx/base: add event queue operation to do polling

Event queue host interface differ on Riverhead and implementation
will be different.

Signed-off-by: Andrew Rybchenko <arybchenko@solarflare.com>
Reviewed-by: Andy Moreton <amoreton@xilinx.com>
This commit is contained in:
Andrew Rybchenko 2020-09-24 13:11:38 +01:00 committed by Ferruh Yigit
parent bb01a80e24
commit ad1e3ed8c5
2 changed files with 182 additions and 145 deletions

View File

@ -66,6 +66,17 @@ siena_ev_qstats_update(
#endif /* EFSYS_OPT_SIENA */
#if EFX_OPTS_EF10() || EFSYS_OPT_SIENA
static void
siena_ef10_ev_qpoll(
__in efx_evq_t *eep,
__inout unsigned int *countp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg);
#endif /* EFX_OPTS_EF10() || EFSYS_OPT_SIENA */
#if EFSYS_OPT_SIENA
static const efx_ev_ops_t __efx_ev_siena_ops = {
siena_ev_init, /* eevo_init */
@ -74,6 +85,7 @@ static const efx_ev_ops_t __efx_ev_siena_ops = {
siena_ev_qdestroy, /* eevo_qdestroy */
siena_ev_qprime, /* eevo_qprime */
siena_ev_qpost, /* eevo_qpost */
siena_ef10_ev_qpoll, /* eevo_qpoll */
siena_ev_qmoderate, /* eevo_qmoderate */
#if EFSYS_OPT_QSTATS
siena_ev_qstats_update, /* eevo_qstats_update */
@ -89,6 +101,7 @@ static const efx_ev_ops_t __efx_ev_ef10_ops = {
ef10_ev_qdestroy, /* eevo_qdestroy */
ef10_ev_qprime, /* eevo_qprime */
ef10_ev_qpost, /* eevo_qpost */
siena_ef10_ev_qpoll, /* eevo_qpoll */
ef10_ev_qmoderate, /* eevo_qmoderate */
#if EFSYS_OPT_QSTATS
ef10_ev_qstats_update, /* eevo_qstats_update */
@ -374,8 +387,6 @@ efx_ev_qprefetch(
#endif /* EFSYS_OPT_EV_PREFETCH */
#define EFX_EV_BATCH 8
void
efx_ev_qpoll(
__in efx_evq_t *eep,
@ -383,153 +394,15 @@ efx_ev_qpoll(
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
efx_qword_t ev[EFX_EV_BATCH];
unsigned int batch;
unsigned int total;
unsigned int count;
unsigned int index;
size_t offset;
/* Ensure events codes match for EF10 (Huntington/Medford) and Siena */
EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_LBN == FSF_AZ_EV_CODE_LBN);
EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_WIDTH == FSF_AZ_EV_CODE_WIDTH);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_RX_EV == FSE_AZ_EV_CODE_RX_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_TX_EV == FSE_AZ_EV_CODE_TX_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRIVER_EV == FSE_AZ_EV_CODE_DRIVER_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRV_GEN_EV ==
FSE_AZ_EV_CODE_DRV_GEN_EV);
#if EFSYS_OPT_MCDI
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_MCDI_EV ==
FSE_AZ_EV_CODE_MCDI_EVRESPONSE);
#endif
efx_nic_t *enp = eep->ee_enp;
const efx_ev_ops_t *eevop = enp->en_eevop;
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
EFSYS_ASSERT(countp != NULL);
EFSYS_ASSERT(eecp != NULL);
count = *countp;
do {
/* Read up until the end of the batch period */
batch = EFX_EV_BATCH - (count & (EFX_EV_BATCH - 1));
offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
for (total = 0; total < batch; ++total) {
EFSYS_MEM_READQ(eep->ee_esmp, offset, &(ev[total]));
EFSYS_ASSERT(eevop != NULL &&
eevop->eevo_qpoll != NULL);
if (!EFX_EV_PRESENT(ev[total]))
break;
EFSYS_PROBE3(event, unsigned int, eep->ee_index,
uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_1),
uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_0));
offset += sizeof (efx_qword_t);
}
#if EFSYS_OPT_EV_PREFETCH && (EFSYS_OPT_EV_PREFETCH_PERIOD > 1)
/*
* Prefetch the next batch when we get within PREFETCH_PERIOD
* of a completed batch. If the batch is smaller, then prefetch
* immediately.
*/
if (total == batch && total < EFSYS_OPT_EV_PREFETCH_PERIOD)
EFSYS_MEM_PREFETCH(eep->ee_esmp, offset);
#endif /* EFSYS_OPT_EV_PREFETCH */
/* Process the batch of events */
for (index = 0; index < total; ++index) {
boolean_t should_abort;
uint32_t code;
#if EFSYS_OPT_EV_PREFETCH
/* Prefetch if we've now reached the batch period */
if (total == batch &&
index + EFSYS_OPT_EV_PREFETCH_PERIOD == total) {
offset = (count + batch) & eep->ee_mask;
offset *= sizeof (efx_qword_t);
EFSYS_MEM_PREFETCH(eep->ee_esmp, offset);
}
#endif /* EFSYS_OPT_EV_PREFETCH */
EFX_EV_QSTAT_INCR(eep, EV_ALL);
code = EFX_QWORD_FIELD(ev[index], FSF_AZ_EV_CODE);
switch (code) {
case FSE_AZ_EV_CODE_RX_EV:
should_abort = eep->ee_rx(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_TX_EV:
should_abort = eep->ee_tx(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_DRIVER_EV:
should_abort = eep->ee_driver(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_DRV_GEN_EV:
should_abort = eep->ee_drv_gen(eep,
&(ev[index]), eecp, arg);
break;
#if EFSYS_OPT_MCDI
case FSE_AZ_EV_CODE_MCDI_EVRESPONSE:
should_abort = eep->ee_mcdi(eep,
&(ev[index]), eecp, arg);
break;
#endif
case FSE_AZ_EV_CODE_GLOBAL_EV:
if (eep->ee_global) {
should_abort = eep->ee_global(eep,
&(ev[index]), eecp, arg);
break;
}
/* else fallthrough */
default:
EFSYS_PROBE3(bad_event,
unsigned int, eep->ee_index,
uint32_t,
EFX_QWORD_FIELD(ev[index], EFX_DWORD_1),
uint32_t,
EFX_QWORD_FIELD(ev[index], EFX_DWORD_0));
EFSYS_ASSERT(eecp->eec_exception != NULL);
(void) eecp->eec_exception(arg,
EFX_EXCEPTION_EV_ERROR, code);
should_abort = B_TRUE;
}
if (should_abort) {
/* Ignore subsequent events */
total = index + 1;
/*
* Poison batch to ensure the outer
* loop is broken out of.
*/
EFSYS_ASSERT(batch <= EFX_EV_BATCH);
batch += (EFX_EV_BATCH << 1);
EFSYS_ASSERT(total != batch);
break;
}
}
/*
* Now that the hardware has most likely moved onto dma'ing
* into the next cache line, clear the processed events. Take
* care to only clear out events that we've processed
*/
EFX_SET_QWORD(ev[0]);
offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
for (index = 0; index < total; ++index) {
EFSYS_MEM_WRITEQ(eep->ee_esmp, offset, &(ev[0]));
offset += sizeof (efx_qword_t);
}
count += total;
} while (total == batch);
*countp = count;
eevop->eevo_qpoll(eep, countp, eecp, arg);
}
void
@ -1484,3 +1357,165 @@ siena_ev_fini(
}
#endif /* EFSYS_OPT_SIENA */
#if EFX_OPTS_EF10() || EFSYS_OPT_SIENA
#define EFX_EV_BATCH 8
static void
siena_ef10_ev_qpoll(
__in efx_evq_t *eep,
__inout unsigned int *countp,
__in const efx_ev_callbacks_t *eecp,
__in_opt void *arg)
{
efx_qword_t ev[EFX_EV_BATCH];
unsigned int batch;
unsigned int total;
unsigned int count;
unsigned int index;
size_t offset;
/* Ensure events codes match for EF10 (Huntington/Medford) and Siena */
EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_LBN == FSF_AZ_EV_CODE_LBN);
EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_WIDTH == FSF_AZ_EV_CODE_WIDTH);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_RX_EV == FSE_AZ_EV_CODE_RX_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_TX_EV == FSE_AZ_EV_CODE_TX_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRIVER_EV == FSE_AZ_EV_CODE_DRIVER_EV);
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRV_GEN_EV ==
FSE_AZ_EV_CODE_DRV_GEN_EV);
#if EFSYS_OPT_MCDI
EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_MCDI_EV ==
FSE_AZ_EV_CODE_MCDI_EVRESPONSE);
#endif
EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC);
EFSYS_ASSERT(countp != NULL);
EFSYS_ASSERT(eecp != NULL);
count = *countp;
do {
/* Read up until the end of the batch period */
batch = EFX_EV_BATCH - (count & (EFX_EV_BATCH - 1));
offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
for (total = 0; total < batch; ++total) {
EFSYS_MEM_READQ(eep->ee_esmp, offset, &(ev[total]));
if (!EFX_EV_PRESENT(ev[total]))
break;
EFSYS_PROBE3(event, unsigned int, eep->ee_index,
uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_1),
uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_0));
offset += sizeof (efx_qword_t);
}
#if EFSYS_OPT_EV_PREFETCH && (EFSYS_OPT_EV_PREFETCH_PERIOD > 1)
/*
* Prefetch the next batch when we get within PREFETCH_PERIOD
* of a completed batch. If the batch is smaller, then prefetch
* immediately.
*/
if (total == batch && total < EFSYS_OPT_EV_PREFETCH_PERIOD)
EFSYS_MEM_PREFETCH(eep->ee_esmp, offset);
#endif /* EFSYS_OPT_EV_PREFETCH */
/* Process the batch of events */
for (index = 0; index < total; ++index) {
boolean_t should_abort;
uint32_t code;
#if EFSYS_OPT_EV_PREFETCH
/* Prefetch if we've now reached the batch period */
if (total == batch &&
index + EFSYS_OPT_EV_PREFETCH_PERIOD == total) {
offset = (count + batch) & eep->ee_mask;
offset *= sizeof (efx_qword_t);
EFSYS_MEM_PREFETCH(eep->ee_esmp, offset);
}
#endif /* EFSYS_OPT_EV_PREFETCH */
EFX_EV_QSTAT_INCR(eep, EV_ALL);
code = EFX_QWORD_FIELD(ev[index], FSF_AZ_EV_CODE);
switch (code) {
case FSE_AZ_EV_CODE_RX_EV:
should_abort = eep->ee_rx(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_TX_EV:
should_abort = eep->ee_tx(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_DRIVER_EV:
should_abort = eep->ee_driver(eep,
&(ev[index]), eecp, arg);
break;
case FSE_AZ_EV_CODE_DRV_GEN_EV:
should_abort = eep->ee_drv_gen(eep,
&(ev[index]), eecp, arg);
break;
#if EFSYS_OPT_MCDI
case FSE_AZ_EV_CODE_MCDI_EVRESPONSE:
should_abort = eep->ee_mcdi(eep,
&(ev[index]), eecp, arg);
break;
#endif
case FSE_AZ_EV_CODE_GLOBAL_EV:
if (eep->ee_global) {
should_abort = eep->ee_global(eep,
&(ev[index]), eecp, arg);
break;
}
/* else fallthrough */
default:
EFSYS_PROBE3(bad_event,
unsigned int, eep->ee_index,
uint32_t,
EFX_QWORD_FIELD(ev[index], EFX_DWORD_1),
uint32_t,
EFX_QWORD_FIELD(ev[index], EFX_DWORD_0));
EFSYS_ASSERT(eecp->eec_exception != NULL);
(void) eecp->eec_exception(arg,
EFX_EXCEPTION_EV_ERROR, code);
should_abort = B_TRUE;
}
if (should_abort) {
/* Ignore subsequent events */
total = index + 1;
/*
* Poison batch to ensure the outer
* loop is broken out of.
*/
EFSYS_ASSERT(batch <= EFX_EV_BATCH);
batch += (EFX_EV_BATCH << 1);
EFSYS_ASSERT(total != batch);
break;
}
}
/*
* Now that the hardware has most likely moved onto dma'ing
* into the next cache line, clear the processed events. Take
* care to only clear out events that we've processed
*/
EFX_SET_QWORD(ev[0]);
offset = (count & eep->ee_mask) * sizeof (efx_qword_t);
for (index = 0; index < total; ++index) {
EFSYS_MEM_WRITEQ(eep->ee_esmp, offset, &(ev[0]));
offset += sizeof (efx_qword_t);
}
count += total;
} while (total == batch);
*countp = count;
}
#endif /* EFX_OPTS_EF10() || EFSYS_OPT_SIENA */

View File

@ -85,6 +85,8 @@ typedef struct efx_ev_ops_s {
void (*eevo_qdestroy)(efx_evq_t *);
efx_rc_t (*eevo_qprime)(efx_evq_t *, unsigned int);
void (*eevo_qpost)(efx_evq_t *, uint16_t);
void (*eevo_qpoll)(efx_evq_t *, unsigned int *,
const efx_ev_callbacks_t *, void *);
efx_rc_t (*eevo_qmoderate)(efx_evq_t *, unsigned int);
#if EFSYS_OPT_QSTATS
void (*eevo_qstats_update)(efx_evq_t *, efsys_stat_t *);