Index: head/sys/dev/sfxge/common/efx_ev.c =================================================================== --- head/sys/dev/sfxge/common/efx_ev.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_ev.c (revision 299517) @@ -1,1420 +1,1420 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_MON_MCDI #include "mcdi_mon.h" #endif #if EFSYS_OPT_QSTATS #define EFX_EV_QSTAT_INCR(_eep, _stat) \ do { \ (_eep)->ee_stat[_stat]++; \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #else #define EFX_EV_QSTAT_INCR(_eep, _stat) #endif #define EFX_EV_PRESENT(_qword) \ (EFX_QWORD_FIELD((_qword), EFX_DWORD_0) != 0xffffffff && \ EFX_QWORD_FIELD((_qword), EFX_DWORD_1) != 0xffffffff) #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_ev_init( __in efx_nic_t *enp); static void falconsiena_ev_fini( __in efx_nic_t *enp); static __checkReturn efx_rc_t falconsiena_ev_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in efx_evq_t *eep); static void falconsiena_ev_qdestroy( __in efx_evq_t *eep); static __checkReturn efx_rc_t falconsiena_ev_qprime( __in efx_evq_t *eep, __in unsigned int count); static void falconsiena_ev_qpoll( __in efx_evq_t *eep, __inout unsigned int *countp, __in const efx_ev_callbacks_t *eecp, __in_opt void *arg); static void falconsiena_ev_qpost( __in efx_evq_t *eep, __in uint16_t data); static __checkReturn efx_rc_t falconsiena_ev_qmoderate( __in efx_evq_t *eep, __in unsigned int us); #if EFSYS_OPT_QSTATS static void falconsiena_ev_qstats_update( __in efx_evq_t *eep, __inout_ecount(EV_NQSTATS) efsys_stat_t *stat); #endif #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_SIENA -static efx_ev_ops_t __efx_ev_siena_ops = { +static const efx_ev_ops_t __efx_ev_siena_ops = { falconsiena_ev_init, /* eevo_init */ falconsiena_ev_fini, /* eevo_fini */ falconsiena_ev_qcreate, /* eevo_qcreate */ falconsiena_ev_qdestroy, /* eevo_qdestroy */ falconsiena_ev_qprime, /* eevo_qprime */ falconsiena_ev_qpost, /* eevo_qpost */ falconsiena_ev_qmoderate, /* eevo_qmoderate */ #if EFSYS_OPT_QSTATS falconsiena_ev_qstats_update, /* eevo_qstats_update */ #endif }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_ev_ops_t __efx_ev_ef10_ops = { +static const efx_ev_ops_t __efx_ev_ef10_ops = { ef10_ev_init, /* eevo_init */ ef10_ev_fini, /* eevo_fini */ ef10_ev_qcreate, /* eevo_qcreate */ ef10_ev_qdestroy, /* eevo_qdestroy */ ef10_ev_qprime, /* eevo_qprime */ ef10_ev_qpost, /* eevo_qpost */ ef10_ev_qmoderate, /* eevo_qmoderate */ #if EFSYS_OPT_QSTATS ef10_ev_qstats_update, /* eevo_qstats_update */ #endif }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_ev_init( __in efx_nic_t *enp) { - efx_ev_ops_t *eevop; + const efx_ev_ops_t *eevop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); if (enp->en_mod_flags & EFX_MOD_EV) { rc = EINVAL; goto fail1; } switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - eevop = (efx_ev_ops_t *)&__efx_ev_siena_ops; + eevop = &__efx_ev_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - eevop = (efx_ev_ops_t *)&__efx_ev_ef10_ops; + eevop = &__efx_ev_ef10_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - eevop = (efx_ev_ops_t *)&__efx_ev_ef10_ops; + eevop = &__efx_ev_ef10_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail1; } EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0); if ((rc = eevop->eevo_init(enp)) != 0) goto fail2; enp->en_eevop = eevop; enp->en_mod_flags |= EFX_MOD_EV; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); enp->en_eevop = NULL; enp->en_mod_flags &= ~EFX_MOD_EV; return (rc); } void efx_ev_fini( __in efx_nic_t *enp) { - efx_ev_ops_t *eevop = enp->en_eevop; + const efx_ev_ops_t *eevop = enp->en_eevop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0); eevop->eevo_fini(enp); enp->en_eevop = NULL; enp->en_mod_flags &= ~EFX_MOD_EV; } __checkReturn efx_rc_t efx_ev_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __deref_out efx_evq_t **eepp) { - efx_ev_ops_t *eevop = enp->en_eevop; + const efx_ev_ops_t *eevop = enp->en_eevop; efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_evq_t *eep; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV); EFSYS_ASSERT3U(enp->en_ev_qcount + 1, <, encp->enc_evq_limit); /* Allocate an EVQ object */ EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_evq_t), eep); if (eep == NULL) { rc = ENOMEM; goto fail1; } eep->ee_magic = EFX_EVQ_MAGIC; eep->ee_enp = enp; eep->ee_index = index; eep->ee_mask = n - 1; eep->ee_esmp = esmp; if ((rc = eevop->eevo_qcreate(enp, index, esmp, n, id, eep)) != 0) goto fail2; enp->en_ev_qcount++; *eepp = eep; return (0); fail2: EFSYS_PROBE(fail2); EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_ev_qdestroy( __in efx_evq_t *eep) { efx_nic_t *enp = eep->ee_enp; - efx_ev_ops_t *eevop = enp->en_eevop; + const efx_ev_ops_t *eevop = enp->en_eevop; EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); EFSYS_ASSERT(enp->en_ev_qcount != 0); --enp->en_ev_qcount; eevop->eevo_qdestroy(eep); /* Free the EVQ object */ EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep); } __checkReturn efx_rc_t efx_ev_qprime( __in efx_evq_t *eep, __in unsigned int count) { efx_nic_t *enp = eep->ee_enp; - efx_ev_ops_t *eevop = enp->en_eevop; + const efx_ev_ops_t *eevop = enp->en_eevop; efx_rc_t rc; EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); if (!(enp->en_mod_flags & EFX_MOD_INTR)) { rc = EINVAL; goto fail1; } if ((rc = eevop->eevo_qprime(eep, count)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn boolean_t efx_ev_qpending( __in efx_evq_t *eep, __in unsigned int count) { size_t offset; efx_qword_t qword; EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); offset = (count & eep->ee_mask) * sizeof (efx_qword_t); EFSYS_MEM_READQ(eep->ee_esmp, offset, &qword); return (EFX_EV_PRESENT(qword)); } #if EFSYS_OPT_EV_PREFETCH void efx_ev_qprefetch( __in efx_evq_t *eep, __in unsigned int count) { efx_nic_t *enp = eep->ee_enp; unsigned int offset; EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); offset = (count & eep->ee_mask) * sizeof (efx_qword_t); EFSYS_MEM_PREFETCH(eep->ee_esmp, offset); } #endif /* EFSYS_OPT_EV_PREFETCH */ void efx_ev_qpoll( __in efx_evq_t *eep, __inout unsigned int *countp, __in const efx_ev_callbacks_t *eecp, __in_opt void *arg) { EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); /* * FIXME: Huntington will require support for hardware event batching * and merging, which will need a different ev_qpoll implementation. * * Without those features the Falcon/Siena code can be used unchanged. */ 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 falconsiena_ev_qpoll(eep, countp, eecp, arg); } void efx_ev_qpost( __in efx_evq_t *eep, __in uint16_t data) { efx_nic_t *enp = eep->ee_enp; - efx_ev_ops_t *eevop = enp->en_eevop; + const efx_ev_ops_t *eevop = enp->en_eevop; EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); EFSYS_ASSERT(eevop != NULL && eevop->eevo_qpost != NULL); eevop->eevo_qpost(eep, data); } __checkReturn efx_rc_t efx_ev_qmoderate( __in efx_evq_t *eep, __in unsigned int us) { efx_nic_t *enp = eep->ee_enp; - efx_ev_ops_t *eevop = enp->en_eevop; + const efx_ev_ops_t *eevop = enp->en_eevop; efx_rc_t rc; EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); if ((rc = eevop->eevo_qmoderate(eep, us)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_QSTATS void efx_ev_qstats_update( __in efx_evq_t *eep, __inout_ecount(EV_NQSTATS) efsys_stat_t *stat) { efx_nic_t *enp = eep->ee_enp; - efx_ev_ops_t *eevop = enp->en_eevop; + const efx_ev_ops_t *eevop = enp->en_eevop; EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); eevop->eevo_qstats_update(eep, stat); } #endif /* EFSYS_OPT_QSTATS */ #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_ev_init( __in efx_nic_t *enp) { efx_oword_t oword; /* * Program the event queue for receive and transmit queue * flush events. */ EFX_BAR_READO(enp, FR_AZ_DP_CTRL_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_FLS_EVQ_ID, 0); EFX_BAR_WRITEO(enp, FR_AZ_DP_CTRL_REG, &oword); return (0); } static __checkReturn boolean_t falconsiena_ev_rx_not_ok( __in efx_evq_t *eep, __in efx_qword_t *eqp, __in uint32_t label, __in uint32_t id, __inout uint16_t *flagsp) { boolean_t ignore = B_FALSE; if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_TOBE_DISC) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_TOBE_DISC); EFSYS_PROBE(tobe_disc); /* * Assume this is a unicast address mismatch, unless below * we find either FSF_AZ_RX_EV_ETH_CRC_ERR or * EV_RX_PAUSE_FRM_ERR is set. */ (*flagsp) |= EFX_ADDR_MISMATCH; } if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_FRM_TRUNC) != 0) { EFSYS_PROBE2(frm_trunc, uint32_t, label, uint32_t, id); EFX_EV_QSTAT_INCR(eep, EV_RX_FRM_TRUNC); (*flagsp) |= EFX_DISCARD; #if EFSYS_OPT_RX_SCATTER /* * Lookout for payload queue ran dry errors and ignore them. * * Sadly for the header/data split cases, the descriptor * pointer in this event refers to the header queue and * therefore cannot be easily detected as duplicate. * So we drop these and rely on the receive processing seeing * a subsequent packet with FSF_AZ_RX_EV_SOP set to discard * the partially received packet. */ if ((EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_SOP) == 0) && (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_JUMBO_CONT) == 0) && (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_BYTE_CNT) == 0)) ignore = B_TRUE; #endif /* EFSYS_OPT_RX_SCATTER */ } if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_ETH_CRC_ERR) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_ETH_CRC_ERR); EFSYS_PROBE(crc_err); (*flagsp) &= ~EFX_ADDR_MISMATCH; (*flagsp) |= EFX_DISCARD; } if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PAUSE_FRM_ERR) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_PAUSE_FRM_ERR); EFSYS_PROBE(pause_frm_err); (*flagsp) &= ~EFX_ADDR_MISMATCH; (*flagsp) |= EFX_DISCARD; } if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_BUF_OWNER_ID_ERR) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_BUF_OWNER_ID_ERR); EFSYS_PROBE(owner_id_err); (*flagsp) |= EFX_DISCARD; } if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_IPV4_HDR_CHKSUM_ERR); EFSYS_PROBE(ipv4_err); (*flagsp) &= ~EFX_CKSUM_IPV4; } if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_UDP_CHKSUM_ERR); EFSYS_PROBE(udp_chk_err); (*flagsp) &= ~EFX_CKSUM_TCPUDP; } if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_IP_FRAG_ERR) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_IP_FRAG_ERR); /* * If IP is fragmented FSF_AZ_RX_EV_IP_FRAG_ERR is set. This * causes FSF_AZ_RX_EV_PKT_OK to be clear. This is not an error * condition. */ (*flagsp) &= ~(EFX_PKT_TCP | EFX_PKT_UDP | EFX_CKSUM_TCPUDP); } return (ignore); } static __checkReturn boolean_t falconsiena_ev_rx( __in efx_evq_t *eep, __in efx_qword_t *eqp, __in const efx_ev_callbacks_t *eecp, __in_opt void *arg) { uint32_t id; uint32_t size; uint32_t label; boolean_t ok; #if EFSYS_OPT_RX_SCATTER boolean_t sop; boolean_t jumbo_cont; #endif /* EFSYS_OPT_RX_SCATTER */ uint32_t hdr_type; boolean_t is_v6; uint16_t flags; boolean_t ignore; boolean_t should_abort; EFX_EV_QSTAT_INCR(eep, EV_RX); /* Basic packet information */ id = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_DESC_PTR); size = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_BYTE_CNT); label = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_Q_LABEL); ok = (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PKT_OK) != 0); #if EFSYS_OPT_RX_SCATTER sop = (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_SOP) != 0); jumbo_cont = (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_JUMBO_CONT) != 0); #endif /* EFSYS_OPT_RX_SCATTER */ hdr_type = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_HDR_TYPE); is_v6 = (EFX_QWORD_FIELD(*eqp, FSF_CZ_RX_EV_IPV6_PKT) != 0); /* * If packet is marked as OK and packet type is TCP/IP or * UDP/IP or other IP, then we can rely on the hardware checksums. */ switch (hdr_type) { case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_TCP: flags = EFX_PKT_TCP | EFX_CKSUM_TCPUDP; if (is_v6) { EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV6); flags |= EFX_PKT_IPV6; } else { EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV4); flags |= EFX_PKT_IPV4 | EFX_CKSUM_IPV4; } break; case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_UDP: flags = EFX_PKT_UDP | EFX_CKSUM_TCPUDP; if (is_v6) { EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV6); flags |= EFX_PKT_IPV6; } else { EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV4); flags |= EFX_PKT_IPV4 | EFX_CKSUM_IPV4; } break; case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_OTHER: if (is_v6) { EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV6); flags = EFX_PKT_IPV6; } else { EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV4); flags = EFX_PKT_IPV4 | EFX_CKSUM_IPV4; } break; case FSE_AZ_RX_EV_HDR_TYPE_OTHER: EFX_EV_QSTAT_INCR(eep, EV_RX_NON_IP); flags = 0; break; default: EFSYS_ASSERT(B_FALSE); flags = 0; break; } #if EFSYS_OPT_RX_SCATTER /* Report scatter and header/lookahead split buffer flags */ if (sop) flags |= EFX_PKT_START; if (jumbo_cont) flags |= EFX_PKT_CONT; #endif /* EFSYS_OPT_RX_SCATTER */ /* Detect errors included in the FSF_AZ_RX_EV_PKT_OK indication */ if (!ok) { ignore = falconsiena_ev_rx_not_ok(eep, eqp, label, id, &flags); if (ignore) { EFSYS_PROBE4(rx_complete, uint32_t, label, uint32_t, id, uint32_t, size, uint16_t, flags); return (B_FALSE); } } /* If we're not discarding the packet then it is ok */ if (~flags & EFX_DISCARD) EFX_EV_QSTAT_INCR(eep, EV_RX_OK); /* Detect multicast packets that didn't match the filter */ if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_MCAST_PKT) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_MCAST_PKT); if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_MCAST_HASH_MATCH) != 0) { EFX_EV_QSTAT_INCR(eep, EV_RX_MCAST_HASH_MATCH); } else { EFSYS_PROBE(mcast_mismatch); flags |= EFX_ADDR_MISMATCH; } } else { flags |= EFX_PKT_UNICAST; } /* * The packet parser in Siena can abort parsing packets under * certain error conditions, setting the PKT_NOT_PARSED bit * (which clears PKT_OK). If this is set, then don't trust * the PKT_TYPE field. */ if (!ok) { uint32_t parse_err; parse_err = EFX_QWORD_FIELD(*eqp, FSF_CZ_RX_EV_PKT_NOT_PARSED); if (parse_err != 0) flags |= EFX_CHECK_VLAN; } if (~flags & EFX_CHECK_VLAN) { uint32_t pkt_type; pkt_type = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PKT_TYPE); if (pkt_type >= FSE_AZ_RX_EV_PKT_TYPE_VLAN) flags |= EFX_PKT_VLAN_TAGGED; } EFSYS_PROBE4(rx_complete, uint32_t, label, uint32_t, id, uint32_t, size, uint16_t, flags); EFSYS_ASSERT(eecp->eec_rx != NULL); should_abort = eecp->eec_rx(arg, label, id, size, flags); return (should_abort); } static __checkReturn boolean_t falconsiena_ev_tx( __in efx_evq_t *eep, __in efx_qword_t *eqp, __in const efx_ev_callbacks_t *eecp, __in_opt void *arg) { uint32_t id; uint32_t label; boolean_t should_abort; EFX_EV_QSTAT_INCR(eep, EV_TX); if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_COMP) != 0 && EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_ERR) == 0 && EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_TOO_BIG) == 0 && EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_WQ_FF_FULL) == 0) { id = EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_DESC_PTR); label = EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_Q_LABEL); EFSYS_PROBE2(tx_complete, uint32_t, label, uint32_t, id); EFSYS_ASSERT(eecp->eec_tx != NULL); should_abort = eecp->eec_tx(arg, label, id); return (should_abort); } if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_COMP) != 0) EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_ERR) != 0) EFX_EV_QSTAT_INCR(eep, EV_TX_PKT_ERR); if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_TOO_BIG) != 0) EFX_EV_QSTAT_INCR(eep, EV_TX_PKT_TOO_BIG); if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_WQ_FF_FULL) != 0) EFX_EV_QSTAT_INCR(eep, EV_TX_WQ_FF_FULL); EFX_EV_QSTAT_INCR(eep, EV_TX_UNEXPECTED); return (B_FALSE); } static __checkReturn boolean_t falconsiena_ev_global( __in efx_evq_t *eep, __in efx_qword_t *eqp, __in const efx_ev_callbacks_t *eecp, __in_opt void *arg) { _NOTE(ARGUNUSED(eqp, eecp, arg)) EFX_EV_QSTAT_INCR(eep, EV_GLOBAL); return (B_FALSE); } static __checkReturn boolean_t falconsiena_ev_driver( __in efx_evq_t *eep, __in efx_qword_t *eqp, __in const efx_ev_callbacks_t *eecp, __in_opt void *arg) { boolean_t should_abort; EFX_EV_QSTAT_INCR(eep, EV_DRIVER); should_abort = B_FALSE; switch (EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBCODE)) { case FSE_AZ_TX_DESCQ_FLS_DONE_EV: { uint32_t txq_index; EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DESCQ_FLS_DONE); txq_index = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA); EFSYS_PROBE1(tx_descq_fls_done, uint32_t, txq_index); EFSYS_ASSERT(eecp->eec_txq_flush_done != NULL); should_abort = eecp->eec_txq_flush_done(arg, txq_index); break; } case FSE_AZ_RX_DESCQ_FLS_DONE_EV: { uint32_t rxq_index; uint32_t failed; rxq_index = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_RX_DESCQ_ID); failed = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL); EFSYS_ASSERT(eecp->eec_rxq_flush_done != NULL); EFSYS_ASSERT(eecp->eec_rxq_flush_failed != NULL); if (failed) { EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_FAILED); EFSYS_PROBE1(rx_descq_fls_failed, uint32_t, rxq_index); should_abort = eecp->eec_rxq_flush_failed(arg, rxq_index); } else { EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_DONE); EFSYS_PROBE1(rx_descq_fls_done, uint32_t, rxq_index); should_abort = eecp->eec_rxq_flush_done(arg, rxq_index); } break; } case FSE_AZ_EVQ_INIT_DONE_EV: EFSYS_ASSERT(eecp->eec_initialized != NULL); should_abort = eecp->eec_initialized(arg); break; case FSE_AZ_EVQ_NOT_EN_EV: EFSYS_PROBE(evq_not_en); break; case FSE_AZ_SRM_UPD_DONE_EV: { uint32_t code; EFX_EV_QSTAT_INCR(eep, EV_DRIVER_SRM_UPD_DONE); code = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA); EFSYS_ASSERT(eecp->eec_sram != NULL); should_abort = eecp->eec_sram(arg, code); break; } case FSE_AZ_WAKE_UP_EV: { uint32_t id; id = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA); EFSYS_ASSERT(eecp->eec_wake_up != NULL); should_abort = eecp->eec_wake_up(arg, id); break; } case FSE_AZ_TX_PKT_NON_TCP_UDP: EFSYS_PROBE(tx_pkt_non_tcp_udp); break; case FSE_AZ_TIMER_EV: { uint32_t id; id = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA); EFSYS_ASSERT(eecp->eec_timer != NULL); should_abort = eecp->eec_timer(arg, id); break; } case FSE_AZ_RX_DSC_ERROR_EV: EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DSC_ERROR); EFSYS_PROBE(rx_dsc_error); EFSYS_ASSERT(eecp->eec_exception != NULL); should_abort = eecp->eec_exception(arg, EFX_EXCEPTION_RX_DSC_ERROR, 0); break; case FSE_AZ_TX_DSC_ERROR_EV: EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DSC_ERROR); EFSYS_PROBE(tx_dsc_error); EFSYS_ASSERT(eecp->eec_exception != NULL); should_abort = eecp->eec_exception(arg, EFX_EXCEPTION_TX_DSC_ERROR, 0); break; default: break; } return (should_abort); } static __checkReturn boolean_t falconsiena_ev_drv_gen( __in efx_evq_t *eep, __in efx_qword_t *eqp, __in const efx_ev_callbacks_t *eecp, __in_opt void *arg) { uint32_t data; boolean_t should_abort; EFX_EV_QSTAT_INCR(eep, EV_DRV_GEN); data = EFX_QWORD_FIELD(*eqp, FSF_AZ_EV_DATA_DW0); if (data >= ((uint32_t)1 << 16)) { EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); return (B_TRUE); } EFSYS_ASSERT(eecp->eec_software != NULL); should_abort = eecp->eec_software(arg, (uint16_t)data); return (should_abort); } #if EFSYS_OPT_MCDI static __checkReturn boolean_t falconsiena_ev_mcdi( __in efx_evq_t *eep, __in efx_qword_t *eqp, __in const efx_ev_callbacks_t *eecp, __in_opt void *arg) { efx_nic_t *enp = eep->ee_enp; unsigned code; boolean_t should_abort = B_FALSE; EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); if (enp->en_family != EFX_FAMILY_SIENA) goto out; EFSYS_ASSERT(eecp->eec_link_change != NULL); EFSYS_ASSERT(eecp->eec_exception != NULL); #if EFSYS_OPT_MON_STATS EFSYS_ASSERT(eecp->eec_monitor != NULL); #endif EFX_EV_QSTAT_INCR(eep, EV_MCDI_RESPONSE); code = EFX_QWORD_FIELD(*eqp, MCDI_EVENT_CODE); switch (code) { case MCDI_EVENT_CODE_BADSSERT: efx_mcdi_ev_death(enp, EINTR); break; case MCDI_EVENT_CODE_CMDDONE: efx_mcdi_ev_cpl(enp, MCDI_EV_FIELD(eqp, CMDDONE_SEQ), MCDI_EV_FIELD(eqp, CMDDONE_DATALEN), MCDI_EV_FIELD(eqp, CMDDONE_ERRNO)); break; case MCDI_EVENT_CODE_LINKCHANGE: { efx_link_mode_t link_mode; siena_phy_link_ev(enp, eqp, &link_mode); should_abort = eecp->eec_link_change(arg, link_mode); break; } case MCDI_EVENT_CODE_SENSOREVT: { #if EFSYS_OPT_MON_STATS efx_mon_stat_t id; efx_mon_stat_value_t value; efx_rc_t rc; if ((rc = mcdi_mon_ev(enp, eqp, &id, &value)) == 0) should_abort = eecp->eec_monitor(arg, id, value); else if (rc == ENOTSUP) { should_abort = eecp->eec_exception(arg, EFX_EXCEPTION_UNKNOWN_SENSOREVT, MCDI_EV_FIELD(eqp, DATA)); } else EFSYS_ASSERT(rc == ENODEV); /* Wrong port */ #else should_abort = B_FALSE; #endif break; } case MCDI_EVENT_CODE_SCHEDERR: /* Informational only */ break; case MCDI_EVENT_CODE_REBOOT: efx_mcdi_ev_death(enp, EIO); break; case MCDI_EVENT_CODE_MAC_STATS_DMA: #if EFSYS_OPT_MAC_STATS if (eecp->eec_mac_stats != NULL) { eecp->eec_mac_stats(arg, MCDI_EV_FIELD(eqp, MAC_STATS_DMA_GENERATION)); } #endif break; case MCDI_EVENT_CODE_FWALERT: { uint32_t reason = MCDI_EV_FIELD(eqp, FWALERT_REASON); if (reason == MCDI_EVENT_FWALERT_REASON_SRAM_ACCESS) should_abort = eecp->eec_exception(arg, EFX_EXCEPTION_FWALERT_SRAM, MCDI_EV_FIELD(eqp, FWALERT_DATA)); else should_abort = eecp->eec_exception(arg, EFX_EXCEPTION_UNKNOWN_FWALERT, MCDI_EV_FIELD(eqp, DATA)); break; } default: EFSYS_PROBE1(mc_pcol_error, int, code); break; } out: return (should_abort); } #endif /* EFSYS_OPT_MCDI */ static __checkReturn efx_rc_t falconsiena_ev_qprime( __in efx_evq_t *eep, __in unsigned int count) { efx_nic_t *enp = eep->ee_enp; uint32_t rptr; efx_dword_t dword; rptr = count & eep->ee_mask; EFX_POPULATE_DWORD_1(dword, FRF_AZ_EVQ_RPTR, rptr); EFX_BAR_TBL_WRITED(enp, FR_AZ_EVQ_RPTR_REG, eep->ee_index, &dword, B_FALSE); return (0); } #define EFX_EV_BATCH 8 static void falconsiena_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; 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; 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; } static void falconsiena_ev_qpost( __in efx_evq_t *eep, __in uint16_t data) { efx_nic_t *enp = eep->ee_enp; efx_qword_t ev; efx_oword_t oword; EFX_POPULATE_QWORD_2(ev, FSF_AZ_EV_CODE, FSE_AZ_EV_CODE_DRV_GEN_EV, FSF_AZ_EV_DATA_DW0, (uint32_t)data); EFX_POPULATE_OWORD_3(oword, FRF_AZ_DRV_EV_QID, eep->ee_index, EFX_DWORD_0, EFX_QWORD_FIELD(ev, EFX_DWORD_0), EFX_DWORD_1, EFX_QWORD_FIELD(ev, EFX_DWORD_1)); EFX_BAR_WRITEO(enp, FR_AZ_DRV_EV_REG, &oword); } static __checkReturn efx_rc_t falconsiena_ev_qmoderate( __in efx_evq_t *eep, __in unsigned int us) { efx_nic_t *enp = eep->ee_enp; efx_nic_cfg_t *encp = &(enp->en_nic_cfg); unsigned int locked; efx_dword_t dword; efx_rc_t rc; if (us > encp->enc_evq_timer_max_us) { rc = EINVAL; goto fail1; } /* If the value is zero then disable the timer */ if (us == 0) { EFX_POPULATE_DWORD_2(dword, FRF_CZ_TC_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS, FRF_CZ_TC_TIMER_VAL, 0); } else { uint32_t timer_val; /* Calculate the timer value in quanta */ timer_val = us * 1000 / encp->enc_evq_timer_quantum_ns; /* Moderation value is base 0 so we need to deduct 1 */ if (timer_val > 0) timer_val--; EFX_POPULATE_DWORD_2(dword, FRF_CZ_TC_TIMER_MODE, FFE_CZ_TIMER_MODE_INT_HLDOFF, FRF_CZ_TC_TIMER_VAL, timer_val); } locked = (eep->ee_index == 0) ? 1 : 0; EFX_BAR_TBL_WRITED(enp, FR_BZ_TIMER_COMMAND_REGP0, eep->ee_index, &dword, locked); return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t falconsiena_ev_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in efx_evq_t *eep) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); uint32_t size; efx_oword_t oword; efx_rc_t rc; EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MAXNEVS)); EFX_STATIC_ASSERT(ISP2(EFX_EVQ_MINNEVS)); if (!ISP2(n) || (n < EFX_EVQ_MINNEVS) || (n > EFX_EVQ_MAXNEVS)) { rc = EINVAL; goto fail1; } if (index >= encp->enc_evq_limit) { rc = EINVAL; goto fail2; } #if EFSYS_OPT_RX_SCALE if (enp->en_intr.ei_type == EFX_INTR_LINE && index >= EFX_MAXRSS_LEGACY) { rc = EINVAL; goto fail3; } #endif for (size = 0; (1 << size) <= (EFX_EVQ_MAXNEVS / EFX_EVQ_MINNEVS); size++) if ((1 << size) == (int)(n / EFX_EVQ_MINNEVS)) break; if (id + (1 << size) >= encp->enc_buftbl_limit) { rc = EINVAL; goto fail4; } /* Set up the handler table */ eep->ee_rx = falconsiena_ev_rx; eep->ee_tx = falconsiena_ev_tx; eep->ee_driver = falconsiena_ev_driver; eep->ee_global = falconsiena_ev_global; eep->ee_drv_gen = falconsiena_ev_drv_gen; #if EFSYS_OPT_MCDI eep->ee_mcdi = falconsiena_ev_mcdi; #endif /* EFSYS_OPT_MCDI */ /* Set up the new event queue */ EFX_POPULATE_OWORD_1(oword, FRF_CZ_TIMER_Q_EN, 1); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL, index, &oword, B_TRUE); EFX_POPULATE_OWORD_3(oword, FRF_AZ_EVQ_EN, 1, FRF_AZ_EVQ_SIZE, size, FRF_AZ_EVQ_BUF_BASE_ID, id); EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL, index, &oword, B_TRUE); return (0); fail4: EFSYS_PROBE(fail4); #if EFSYS_OPT_RX_SCALE fail3: EFSYS_PROBE(fail3); #endif fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_QSTATS #if EFSYS_OPT_NAMES /* START MKCONFIG GENERATED EfxEventQueueStatNamesBlock b693ddf85aee1bfd */ static const char *__efx_ev_qstat_name[] = { "all", "rx", "rx_ok", "rx_frm_trunc", "rx_tobe_disc", "rx_pause_frm_err", "rx_buf_owner_id_err", "rx_ipv4_hdr_chksum_err", "rx_tcp_udp_chksum_err", "rx_eth_crc_err", "rx_ip_frag_err", "rx_mcast_pkt", "rx_mcast_hash_match", "rx_tcp_ipv4", "rx_tcp_ipv6", "rx_udp_ipv4", "rx_udp_ipv6", "rx_other_ipv4", "rx_other_ipv6", "rx_non_ip", "rx_batch", "tx", "tx_wq_ff_full", "tx_pkt_err", "tx_pkt_too_big", "tx_unexpected", "global", "global_mnt", "driver", "driver_srm_upd_done", "driver_tx_descq_fls_done", "driver_rx_descq_fls_done", "driver_rx_descq_fls_failed", "driver_rx_dsc_error", "driver_tx_dsc_error", "drv_gen", "mcdi_response", }; /* END MKCONFIG GENERATED EfxEventQueueStatNamesBlock */ const char * efx_ev_qstat_name( __in efx_nic_t *enp, __in unsigned int id) { EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(id, <, EV_NQSTATS); return (__efx_ev_qstat_name[id]); } #endif /* EFSYS_OPT_NAMES */ #endif /* EFSYS_OPT_QSTATS */ #if EFSYS_OPT_SIENA #if EFSYS_OPT_QSTATS static void falconsiena_ev_qstats_update( __in efx_evq_t *eep, __inout_ecount(EV_NQSTATS) efsys_stat_t *stat) { unsigned int id; for (id = 0; id < EV_NQSTATS; id++) { efsys_stat_t *essp = &stat[id]; EFSYS_STAT_INCR(essp, eep->ee_stat[id]); eep->ee_stat[id] = 0; } } #endif /* EFSYS_OPT_QSTATS */ static void falconsiena_ev_qdestroy( __in efx_evq_t *eep) { efx_nic_t *enp = eep->ee_enp; efx_oword_t oword; /* Purge event queue */ EFX_ZERO_OWORD(oword); EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL, eep->ee_index, &oword, B_TRUE); EFX_ZERO_OWORD(oword); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL, eep->ee_index, &oword, B_TRUE); } static void falconsiena_ev_fini( __in efx_nic_t *enp) { _NOTE(ARGUNUSED(enp)) } #endif /* EFSYS_OPT_SIENA */ Index: head/sys/dev/sfxge/common/efx_filter.c =================================================================== --- head/sys/dev/sfxge/common/efx_filter.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_filter.c (revision 299517) @@ -1,1414 +1,1414 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_FILTER #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_filter_init( __in efx_nic_t *enp); static void falconsiena_filter_fini( __in efx_nic_t *enp); static __checkReturn efx_rc_t falconsiena_filter_restore( __in efx_nic_t *enp); static __checkReturn efx_rc_t falconsiena_filter_add( __in efx_nic_t *enp, __inout efx_filter_spec_t *spec, __in boolean_t may_replace); static __checkReturn efx_rc_t falconsiena_filter_delete( __in efx_nic_t *enp, __inout efx_filter_spec_t *spec); static __checkReturn efx_rc_t falconsiena_filter_supported_filters( __in efx_nic_t *enp, __out uint32_t *list, __out size_t *length); #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_SIENA -static efx_filter_ops_t __efx_filter_siena_ops = { +static const efx_filter_ops_t __efx_filter_siena_ops = { falconsiena_filter_init, /* efo_init */ falconsiena_filter_fini, /* efo_fini */ falconsiena_filter_restore, /* efo_restore */ falconsiena_filter_add, /* efo_add */ falconsiena_filter_delete, /* efo_delete */ falconsiena_filter_supported_filters, /* efo_supported_filters */ NULL, /* efo_reconfigure */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_filter_ops_t __efx_filter_ef10_ops = { +static const efx_filter_ops_t __efx_filter_ef10_ops = { ef10_filter_init, /* efo_init */ ef10_filter_fini, /* efo_fini */ ef10_filter_restore, /* efo_restore */ ef10_filter_add, /* efo_add */ ef10_filter_delete, /* efo_delete */ ef10_filter_supported_filters, /* efo_supported_filters */ ef10_filter_reconfigure, /* efo_reconfigure */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_filter_insert( __in efx_nic_t *enp, __inout efx_filter_spec_t *spec) { - efx_filter_ops_t *efop = enp->en_efop; + const efx_filter_ops_t *efop = enp->en_efop; EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); EFSYS_ASSERT3P(spec, !=, NULL); EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX); return (efop->efo_add(enp, spec, B_FALSE)); } __checkReturn efx_rc_t efx_filter_remove( __in efx_nic_t *enp, __inout efx_filter_spec_t *spec) { - efx_filter_ops_t *efop = enp->en_efop; + const efx_filter_ops_t *efop = enp->en_efop; EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); EFSYS_ASSERT3P(spec, !=, NULL); EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX); #if EFSYS_OPT_RX_SCALE spec->efs_rss_context = enp->en_rss_context; #endif return (efop->efo_delete(enp, spec)); } __checkReturn efx_rc_t efx_filter_restore( __in efx_nic_t *enp) { efx_rc_t rc; EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); if ((rc = enp->en_efop->efo_restore(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_filter_init( __in efx_nic_t *enp) { - efx_filter_ops_t *efop; + const efx_filter_ops_t *efop; efx_rc_t rc; /* Check that efx_filter_spec_t is 64 bytes. */ EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64); EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER)); switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - efop = (efx_filter_ops_t *)&__efx_filter_siena_ops; + efop = &__efx_filter_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - efop = (efx_filter_ops_t *)&__efx_filter_ef10_ops; + efop = &__efx_filter_ef10_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - efop = (efx_filter_ops_t *)&__efx_filter_ef10_ops; + efop = &__efx_filter_ef10_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail1; } if ((rc = efop->efo_init(enp)) != 0) goto fail2; enp->en_efop = efop; enp->en_mod_flags |= EFX_MOD_FILTER; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); enp->en_efop = NULL; enp->en_mod_flags &= ~EFX_MOD_FILTER; return (rc); } void efx_filter_fini( __in efx_nic_t *enp) { EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); enp->en_efop->efo_fini(enp); enp->en_efop = NULL; enp->en_mod_flags &= ~EFX_MOD_FILTER; } __checkReturn efx_rc_t efx_filter_supported_filters( __in efx_nic_t *enp, __out uint32_t *list, __out size_t *length) { efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL); if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_filter_reconfigure( __in efx_nic_t *enp, __in_ecount(6) uint8_t const *mac_addr, __in boolean_t all_unicst, __in boolean_t mulcst, __in boolean_t all_mulcst, __in boolean_t brdcst, __in_ecount(6*count) uint8_t const *addrs, __in uint32_t count) { efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); if (enp->en_efop->efo_reconfigure != NULL) { if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr, all_unicst, mulcst, all_mulcst, brdcst, addrs, count)) != 0) goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_filter_spec_init_rx( __out efx_filter_spec_t *spec, __in efx_filter_priority_t priority, __in efx_filter_flag_t flags, __in efx_rxq_t *erp) { EFSYS_ASSERT3P(spec, !=, NULL); EFSYS_ASSERT3P(erp, !=, NULL); EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS | EFX_FILTER_FLAG_RX_SCATTER)) == 0); memset(spec, 0, sizeof (*spec)); spec->efs_priority = priority; spec->efs_flags = EFX_FILTER_FLAG_RX | flags; spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT; spec->efs_dmaq_id = (uint16_t)erp->er_index; } void efx_filter_spec_init_tx( __out efx_filter_spec_t *spec, __in efx_txq_t *etp) { EFSYS_ASSERT3P(spec, !=, NULL); EFSYS_ASSERT3P(etp, !=, NULL); memset(spec, 0, sizeof (*spec)); spec->efs_priority = EFX_FILTER_PRI_REQUIRED; spec->efs_flags = EFX_FILTER_FLAG_TX; spec->efs_dmaq_id = (uint16_t)etp->et_index; } /* * Specify IPv4 host, transport protocol and port in a filter specification */ __checkReturn efx_rc_t efx_filter_spec_set_ipv4_local( __inout efx_filter_spec_t *spec, __in uint8_t proto, __in uint32_t host, __in uint16_t port) { EFSYS_ASSERT3P(spec, !=, NULL); spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; spec->efs_ether_type = EFX_ETHER_TYPE_IPV4; spec->efs_ip_proto = proto; spec->efs_loc_host.eo_u32[0] = host; spec->efs_loc_port = port; return (0); } /* * Specify IPv4 hosts, transport protocol and ports in a filter specification */ __checkReturn efx_rc_t efx_filter_spec_set_ipv4_full( __inout efx_filter_spec_t *spec, __in uint8_t proto, __in uint32_t lhost, __in uint16_t lport, __in uint32_t rhost, __in uint16_t rport) { EFSYS_ASSERT3P(spec, !=, NULL); spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; spec->efs_ether_type = EFX_ETHER_TYPE_IPV4; spec->efs_ip_proto = proto; spec->efs_loc_host.eo_u32[0] = lhost; spec->efs_loc_port = lport; spec->efs_rem_host.eo_u32[0] = rhost; spec->efs_rem_port = rport; return (0); } /* * Specify local Ethernet address and/or VID in filter specification */ __checkReturn efx_rc_t efx_filter_spec_set_eth_local( __inout efx_filter_spec_t *spec, __in uint16_t vid, __in const uint8_t *addr) { EFSYS_ASSERT3P(spec, !=, NULL); EFSYS_ASSERT3P(addr, !=, NULL); if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL) return (EINVAL); if (vid != EFX_FILTER_SPEC_VID_UNSPEC) { spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID; spec->efs_outer_vid = vid; } if (addr != NULL) { spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC; memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN); } return (0); } /* * Specify matching otherwise-unmatched unicast in a filter specification */ __checkReturn efx_rc_t efx_filter_spec_set_uc_def( __inout efx_filter_spec_t *spec) { EFSYS_ASSERT3P(spec, !=, NULL); spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG; return (0); } /* * Specify matching otherwise-unmatched multicast in a filter specification */ __checkReturn efx_rc_t efx_filter_spec_set_mc_def( __inout efx_filter_spec_t *spec) { EFSYS_ASSERT3P(spec, !=, NULL); spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG; spec->efs_loc_mac[0] = 1; return (0); } #if EFSYS_OPT_SIENA /* * "Fudge factors" - difference between programmed value and actual depth. * Due to pipelined implementation we need to program H/W with a value that * is larger than the hop limit we want. */ #define FILTER_CTL_SRCH_FUDGE_WILD 3 #define FILTER_CTL_SRCH_FUDGE_FULL 1 /* * Hard maximum hop limit. Hardware will time-out beyond 200-something. * We also need to avoid infinite loops in efx_filter_search() when the * table is full. */ #define FILTER_CTL_SRCH_MAX 200 static __checkReturn efx_rc_t falconsiena_filter_spec_from_gen_spec( __out falconsiena_filter_spec_t *fs_spec, __in efx_filter_spec_t *gen_spec) { efx_rc_t rc; boolean_t is_full = B_FALSE; if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX); else EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX); /* Falconsiena only has one RSS context */ if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) && gen_spec->efs_rss_context != 0) { rc = EINVAL; goto fail1; } fs_spec->fsfs_flags = gen_spec->efs_flags; fs_spec->fsfs_dmaq_id = gen_spec->efs_dmaq_id; switch (gen_spec->efs_match_flags) { case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT: is_full = B_TRUE; /* Fall through */ case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: { uint32_t rhost, host1, host2; uint16_t rport, port1, port2; if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) { rc = ENOTSUP; goto fail2; } if (gen_spec->efs_loc_port == 0 || (is_full && gen_spec->efs_rem_port == 0)) { rc = EINVAL; goto fail3; } switch (gen_spec->efs_ip_proto) { case EFX_IPPROTO_TCP: if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { fs_spec->fsfs_type = (is_full ? EFX_FS_FILTER_TX_TCP_FULL : EFX_FS_FILTER_TX_TCP_WILD); } else { fs_spec->fsfs_type = (is_full ? EFX_FS_FILTER_RX_TCP_FULL : EFX_FS_FILTER_RX_TCP_WILD); } break; case EFX_IPPROTO_UDP: if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { fs_spec->fsfs_type = (is_full ? EFX_FS_FILTER_TX_UDP_FULL : EFX_FS_FILTER_TX_UDP_WILD); } else { fs_spec->fsfs_type = (is_full ? EFX_FS_FILTER_RX_UDP_FULL : EFX_FS_FILTER_RX_UDP_WILD); } break; default: rc = ENOTSUP; goto fail4; } /* * The filter is constructed in terms of source and destination, * with the odd wrinkle that the ports are swapped in a UDP * wildcard filter. We need to convert from local and remote * addresses (zero for a wildcard). */ rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0; rport = is_full ? gen_spec->efs_rem_port : 0; if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { host1 = gen_spec->efs_loc_host.eo_u32[0]; host2 = rhost; } else { host1 = rhost; host2 = gen_spec->efs_loc_host.eo_u32[0]; } if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { if (fs_spec->fsfs_type == EFX_FS_FILTER_TX_UDP_WILD) { port1 = rport; port2 = gen_spec->efs_loc_port; } else { port1 = gen_spec->efs_loc_port; port2 = rport; } } else { if (fs_spec->fsfs_type == EFX_FS_FILTER_RX_UDP_WILD) { port1 = gen_spec->efs_loc_port; port2 = rport; } else { port1 = rport; port2 = gen_spec->efs_loc_port; } } fs_spec->fsfs_dword[0] = (host1 << 16) | port1; fs_spec->fsfs_dword[1] = (port2 << 16) | (host1 >> 16); fs_spec->fsfs_dword[2] = host2; break; } case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID: is_full = B_TRUE; /* Fall through */ case EFX_FILTER_MATCH_LOC_MAC: if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { fs_spec->fsfs_type = (is_full ? EFX_FS_FILTER_TX_MAC_FULL : EFX_FS_FILTER_TX_MAC_WILD); } else { fs_spec->fsfs_type = (is_full ? EFX_FS_FILTER_RX_MAC_FULL : EFX_FS_FILTER_RX_MAC_WILD); } fs_spec->fsfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0; fs_spec->fsfs_dword[1] = gen_spec->efs_loc_mac[2] << 24 | gen_spec->efs_loc_mac[3] << 16 | gen_spec->efs_loc_mac[4] << 8 | gen_spec->efs_loc_mac[5]; fs_spec->fsfs_dword[2] = gen_spec->efs_loc_mac[0] << 8 | gen_spec->efs_loc_mac[1]; break; default: EFSYS_ASSERT(B_FALSE); rc = ENOTSUP; goto fail5; } 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); } /* * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit * key derived from the n-tuple. */ static uint16_t falconsiena_filter_tbl_hash( __in uint32_t key) { uint16_t tmp; /* First 16 rounds */ tmp = 0x1fff ^ (uint16_t)(key >> 16); tmp = tmp ^ tmp >> 3 ^ tmp >> 6; tmp = tmp ^ tmp >> 9; /* Last 16 rounds */ tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff); tmp = tmp ^ tmp >> 3 ^ tmp >> 6; tmp = tmp ^ tmp >> 9; return (tmp); } /* * To allow for hash collisions, filter search continues at these * increments from the first possible entry selected by the hash. */ static uint16_t falconsiena_filter_tbl_increment( __in uint32_t key) { return ((uint16_t)(key * 2 - 1)); } static __checkReturn boolean_t falconsiena_filter_test_used( __in falconsiena_filter_tbl_t *fsftp, __in unsigned int index) { EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL); return ((fsftp->fsft_bitmap[index / 32] & (1 << (index % 32))) != 0); } static void falconsiena_filter_set_used( __in falconsiena_filter_tbl_t *fsftp, __in unsigned int index) { EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL); fsftp->fsft_bitmap[index / 32] |= (1 << (index % 32)); ++fsftp->fsft_used; } static void falconsiena_filter_clear_used( __in falconsiena_filter_tbl_t *fsftp, __in unsigned int index) { EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL); fsftp->fsft_bitmap[index / 32] &= ~(1 << (index % 32)); --fsftp->fsft_used; EFSYS_ASSERT3U(fsftp->fsft_used, >=, 0); } static falconsiena_filter_tbl_id_t falconsiena_filter_tbl_id( __in falconsiena_filter_type_t type) { falconsiena_filter_tbl_id_t tbl_id; switch (type) { case EFX_FS_FILTER_RX_TCP_FULL: case EFX_FS_FILTER_RX_TCP_WILD: case EFX_FS_FILTER_RX_UDP_FULL: case EFX_FS_FILTER_RX_UDP_WILD: tbl_id = EFX_FS_FILTER_TBL_RX_IP; break; #if EFSYS_OPT_SIENA case EFX_FS_FILTER_RX_MAC_FULL: case EFX_FS_FILTER_RX_MAC_WILD: tbl_id = EFX_FS_FILTER_TBL_RX_MAC; break; case EFX_FS_FILTER_TX_TCP_FULL: case EFX_FS_FILTER_TX_TCP_WILD: case EFX_FS_FILTER_TX_UDP_FULL: case EFX_FS_FILTER_TX_UDP_WILD: tbl_id = EFX_FS_FILTER_TBL_TX_IP; break; case EFX_FS_FILTER_TX_MAC_FULL: case EFX_FS_FILTER_TX_MAC_WILD: tbl_id = EFX_FS_FILTER_TBL_TX_MAC; break; #endif /* EFSYS_OPT_SIENA */ default: EFSYS_ASSERT(B_FALSE); tbl_id = EFX_FS_FILTER_NTBLS; break; } return (tbl_id); } static void falconsiena_filter_reset_search_depth( __inout falconsiena_filter_t *fsfp, __in falconsiena_filter_tbl_id_t tbl_id) { switch (tbl_id) { case EFX_FS_FILTER_TBL_RX_IP: fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_FULL] = 0; fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_WILD] = 0; fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_FULL] = 0; fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_WILD] = 0; break; #if EFSYS_OPT_SIENA case EFX_FS_FILTER_TBL_RX_MAC: fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_FULL] = 0; fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_WILD] = 0; break; case EFX_FS_FILTER_TBL_TX_IP: fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_FULL] = 0; fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_WILD] = 0; fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_FULL] = 0; fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_WILD] = 0; break; case EFX_FS_FILTER_TBL_TX_MAC: fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_FULL] = 0; fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_WILD] = 0; break; #endif /* EFSYS_OPT_SIENA */ default: EFSYS_ASSERT(B_FALSE); break; } } static void falconsiena_filter_push_rx_limits( __in efx_nic_t *enp) { falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; efx_oword_t oword; EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT, fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_FULL] + FILTER_CTL_SRCH_FUDGE_FULL); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT, fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_WILD] + FILTER_CTL_SRCH_FUDGE_WILD); EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT, fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_FULL] + FILTER_CTL_SRCH_FUDGE_FULL); EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT, fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_WILD] + FILTER_CTL_SRCH_FUDGE_WILD); #if EFSYS_OPT_SIENA if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_MAC].fsft_size) { EFX_SET_OWORD_FIELD(oword, FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_FULL] + FILTER_CTL_SRCH_FUDGE_FULL); EFX_SET_OWORD_FIELD(oword, FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_WILD] + FILTER_CTL_SRCH_FUDGE_WILD); } #endif /* EFSYS_OPT_SIENA */ EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); } static void falconsiena_filter_push_tx_limits( __in efx_nic_t *enp) { falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; efx_oword_t oword; EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword); if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_IP].fsft_size != 0) { EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE, fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_FULL] + FILTER_CTL_SRCH_FUDGE_FULL); EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE, fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_WILD] + FILTER_CTL_SRCH_FUDGE_WILD); EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE, fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_FULL] + FILTER_CTL_SRCH_FUDGE_FULL); EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE, fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_WILD] + FILTER_CTL_SRCH_FUDGE_WILD); } if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_MAC].fsft_size != 0) { EFX_SET_OWORD_FIELD( oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE, fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_FULL] + FILTER_CTL_SRCH_FUDGE_FULL); EFX_SET_OWORD_FIELD( oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE, fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_WILD] + FILTER_CTL_SRCH_FUDGE_WILD); } EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword); } /* Build a filter entry and return its n-tuple key. */ static __checkReturn uint32_t falconsiena_filter_build( __out efx_oword_t *filter, __in falconsiena_filter_spec_t *spec) { uint32_t dword3; uint32_t key; uint8_t type = spec->fsfs_type; uint32_t flags = spec->fsfs_flags; switch (falconsiena_filter_tbl_id(type)) { case EFX_FS_FILTER_TBL_RX_IP: { boolean_t is_udp = (type == EFX_FS_FILTER_RX_UDP_FULL || type == EFX_FS_FILTER_RX_UDP_WILD); EFX_POPULATE_OWORD_7(*filter, FRF_BZ_RSS_EN, (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, FRF_BZ_SCATTER_EN, (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, FRF_AZ_TCP_UDP, is_udp, FRF_AZ_RXQ_ID, spec->fsfs_dmaq_id, EFX_DWORD_2, spec->fsfs_dword[2], EFX_DWORD_1, spec->fsfs_dword[1], EFX_DWORD_0, spec->fsfs_dword[0]); dword3 = is_udp; break; } #if EFSYS_OPT_SIENA case EFX_FS_FILTER_TBL_RX_MAC: { boolean_t is_wild = (type == EFX_FS_FILTER_RX_MAC_WILD); EFX_POPULATE_OWORD_7(*filter, FRF_CZ_RMFT_RSS_EN, (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, FRF_CZ_RMFT_SCATTER_EN, (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, FRF_CZ_RMFT_RXQ_ID, spec->fsfs_dmaq_id, FRF_CZ_RMFT_WILDCARD_MATCH, is_wild, FRF_CZ_RMFT_DEST_MAC_DW1, spec->fsfs_dword[2], FRF_CZ_RMFT_DEST_MAC_DW0, spec->fsfs_dword[1], FRF_CZ_RMFT_VLAN_ID, spec->fsfs_dword[0]); dword3 = is_wild; break; } #endif /* EFSYS_OPT_SIENA */ case EFX_FS_FILTER_TBL_TX_IP: { boolean_t is_udp = (type == EFX_FS_FILTER_TX_UDP_FULL || type == EFX_FS_FILTER_TX_UDP_WILD); EFX_POPULATE_OWORD_5(*filter, FRF_CZ_TIFT_TCP_UDP, is_udp, FRF_CZ_TIFT_TXQ_ID, spec->fsfs_dmaq_id, EFX_DWORD_2, spec->fsfs_dword[2], EFX_DWORD_1, spec->fsfs_dword[1], EFX_DWORD_0, spec->fsfs_dword[0]); dword3 = is_udp | spec->fsfs_dmaq_id << 1; break; } #if EFSYS_OPT_SIENA case EFX_FS_FILTER_TBL_TX_MAC: { boolean_t is_wild = (type == EFX_FS_FILTER_TX_MAC_WILD); EFX_POPULATE_OWORD_5(*filter, FRF_CZ_TMFT_TXQ_ID, spec->fsfs_dmaq_id, FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, FRF_CZ_TMFT_SRC_MAC_DW1, spec->fsfs_dword[2], FRF_CZ_TMFT_SRC_MAC_DW0, spec->fsfs_dword[1], FRF_CZ_TMFT_VLAN_ID, spec->fsfs_dword[0]); dword3 = is_wild | spec->fsfs_dmaq_id << 1; break; } #endif /* EFSYS_OPT_SIENA */ default: EFSYS_ASSERT(B_FALSE); return (0); } key = spec->fsfs_dword[0] ^ spec->fsfs_dword[1] ^ spec->fsfs_dword[2] ^ dword3; return (key); } static __checkReturn efx_rc_t falconsiena_filter_push_entry( __inout efx_nic_t *enp, __in falconsiena_filter_type_t type, __in int index, __in efx_oword_t *eop) { efx_rc_t rc; switch (type) { case EFX_FS_FILTER_RX_TCP_FULL: case EFX_FS_FILTER_RX_TCP_WILD: case EFX_FS_FILTER_RX_UDP_FULL: case EFX_FS_FILTER_RX_UDP_WILD: EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index, eop, B_TRUE); break; #if EFSYS_OPT_SIENA case EFX_FS_FILTER_RX_MAC_FULL: case EFX_FS_FILTER_RX_MAC_WILD: EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index, eop, B_TRUE); break; case EFX_FS_FILTER_TX_TCP_FULL: case EFX_FS_FILTER_TX_TCP_WILD: case EFX_FS_FILTER_TX_UDP_FULL: case EFX_FS_FILTER_TX_UDP_WILD: EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index, eop, B_TRUE); break; case EFX_FS_FILTER_TX_MAC_FULL: case EFX_FS_FILTER_TX_MAC_WILD: EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index, eop, B_TRUE); break; #endif /* EFSYS_OPT_SIENA */ default: EFSYS_ASSERT(B_FALSE); rc = ENOTSUP; goto fail1; } return (0); fail1: return (rc); } static __checkReturn boolean_t falconsiena_filter_equal( __in const falconsiena_filter_spec_t *left, __in const falconsiena_filter_spec_t *right) { falconsiena_filter_tbl_id_t tbl_id; tbl_id = falconsiena_filter_tbl_id(left->fsfs_type); if (left->fsfs_type != right->fsfs_type) return (B_FALSE); if (memcmp(left->fsfs_dword, right->fsfs_dword, sizeof (left->fsfs_dword))) return (B_FALSE); if ((tbl_id == EFX_FS_FILTER_TBL_TX_IP || tbl_id == EFX_FS_FILTER_TBL_TX_MAC) && left->fsfs_dmaq_id != right->fsfs_dmaq_id) return (B_FALSE); return (B_TRUE); } static __checkReturn efx_rc_t falconsiena_filter_search( __in falconsiena_filter_tbl_t *fsftp, __in falconsiena_filter_spec_t *spec, __in uint32_t key, __in boolean_t for_insert, __out int *filter_index, __out unsigned int *depth_required) { unsigned hash, incr, filter_idx, depth; hash = falconsiena_filter_tbl_hash(key); incr = falconsiena_filter_tbl_increment(key); filter_idx = hash & (fsftp->fsft_size - 1); depth = 1; for (;;) { /* * Return success if entry is used and matches this spec * or entry is unused and we are trying to insert. */ if (falconsiena_filter_test_used(fsftp, filter_idx) ? falconsiena_filter_equal(spec, &fsftp->fsft_spec[filter_idx]) : for_insert) { *filter_index = filter_idx; *depth_required = depth; return (0); } /* Return failure if we reached the maximum search depth */ if (depth == FILTER_CTL_SRCH_MAX) return (for_insert ? EBUSY : ENOENT); filter_idx = (filter_idx + incr) & (fsftp->fsft_size - 1); ++depth; } } static void falconsiena_filter_clear_entry( __in efx_nic_t *enp, __in falconsiena_filter_tbl_t *fsftp, __in int index) { efx_oword_t filter; if (falconsiena_filter_test_used(fsftp, index)) { falconsiena_filter_clear_used(fsftp, index); EFX_ZERO_OWORD(filter); falconsiena_filter_push_entry(enp, fsftp->fsft_spec[index].fsfs_type, index, &filter); memset(&fsftp->fsft_spec[index], 0, sizeof (fsftp->fsft_spec[0])); } } void falconsiena_filter_tbl_clear( __in efx_nic_t *enp, __in falconsiena_filter_tbl_id_t tbl_id) { falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; falconsiena_filter_tbl_t *fsftp = &fsfp->fsf_tbl[tbl_id]; int index; int state; EFSYS_LOCK(enp->en_eslp, state); for (index = 0; index < fsftp->fsft_size; ++index) { falconsiena_filter_clear_entry(enp, fsftp, index); } if (fsftp->fsft_used == 0) falconsiena_filter_reset_search_depth(fsfp, tbl_id); EFSYS_UNLOCK(enp->en_eslp, state); } static __checkReturn efx_rc_t falconsiena_filter_init( __in efx_nic_t *enp) { falconsiena_filter_t *fsfp; falconsiena_filter_tbl_t *fsftp; int tbl_id; efx_rc_t rc; EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (falconsiena_filter_t), fsfp); if (!fsfp) { rc = ENOMEM; goto fail1; } enp->en_filter.ef_falconsiena_filter = fsfp; switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_IP]; fsftp->fsft_size = FR_AZ_RX_FILTER_TBL0_ROWS; fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_MAC]; fsftp->fsft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS; fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_IP]; fsftp->fsft_size = FR_CZ_TX_FILTER_TBL0_ROWS; fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_MAC]; fsftp->fsft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS; break; #endif /* EFSYS_OPT_SIENA */ default: rc = ENOTSUP; goto fail2; } for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) { unsigned int bitmap_size; fsftp = &fsfp->fsf_tbl[tbl_id]; if (fsftp->fsft_size == 0) continue; EFX_STATIC_ASSERT(sizeof (fsftp->fsft_bitmap[0]) == sizeof (uint32_t)); bitmap_size = (fsftp->fsft_size + (sizeof (uint32_t) * 8) - 1) / 8; EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, fsftp->fsft_bitmap); if (!fsftp->fsft_bitmap) { rc = ENOMEM; goto fail3; } EFSYS_KMEM_ALLOC(enp->en_esip, fsftp->fsft_size * sizeof (*fsftp->fsft_spec), fsftp->fsft_spec); if (!fsftp->fsft_spec) { rc = ENOMEM; goto fail4; } memset(fsftp->fsft_spec, 0, fsftp->fsft_size * sizeof (*fsftp->fsft_spec)); } return (0); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); falconsiena_filter_fini(enp); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static void falconsiena_filter_fini( __in efx_nic_t *enp) { falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; falconsiena_filter_tbl_id_t tbl_id; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); if (fsfp == NULL) return; for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) { falconsiena_filter_tbl_t *fsftp = &fsfp->fsf_tbl[tbl_id]; unsigned int bitmap_size; EFX_STATIC_ASSERT(sizeof (fsftp->fsft_bitmap[0]) == sizeof (uint32_t)); bitmap_size = (fsftp->fsft_size + (sizeof (uint32_t) * 8) - 1) / 8; if (fsftp->fsft_bitmap != NULL) { EFSYS_KMEM_FREE(enp->en_esip, bitmap_size, fsftp->fsft_bitmap); fsftp->fsft_bitmap = NULL; } if (fsftp->fsft_spec != NULL) { EFSYS_KMEM_FREE(enp->en_esip, fsftp->fsft_size * sizeof (*fsftp->fsft_spec), fsftp->fsft_spec); fsftp->fsft_spec = NULL; } } EFSYS_KMEM_FREE(enp->en_esip, sizeof (falconsiena_filter_t), enp->en_filter.ef_falconsiena_filter); } /* Restore filter state after a reset */ static __checkReturn efx_rc_t falconsiena_filter_restore( __in efx_nic_t *enp) { falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; falconsiena_filter_tbl_id_t tbl_id; falconsiena_filter_tbl_t *fsftp; falconsiena_filter_spec_t *spec; efx_oword_t filter; int filter_idx; int state; efx_rc_t rc; EFSYS_LOCK(enp->en_eslp, state); for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) { fsftp = &fsfp->fsf_tbl[tbl_id]; for (filter_idx = 0; filter_idx < fsftp->fsft_size; filter_idx++) { if (!falconsiena_filter_test_used(fsftp, filter_idx)) continue; spec = &fsftp->fsft_spec[filter_idx]; if ((rc = falconsiena_filter_build(&filter, spec)) != 0) goto fail1; if ((rc = falconsiena_filter_push_entry(enp, spec->fsfs_type, filter_idx, &filter)) != 0) goto fail2; } } falconsiena_filter_push_rx_limits(enp); falconsiena_filter_push_tx_limits(enp); EFSYS_UNLOCK(enp->en_eslp, state); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); EFSYS_UNLOCK(enp->en_eslp, state); return (rc); } static __checkReturn efx_rc_t falconsiena_filter_add( __in efx_nic_t *enp, __inout efx_filter_spec_t *spec, __in boolean_t may_replace) { efx_rc_t rc; falconsiena_filter_spec_t fs_spec; falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; falconsiena_filter_tbl_id_t tbl_id; falconsiena_filter_tbl_t *fsftp; falconsiena_filter_spec_t *saved_fs_spec; efx_oword_t filter; int filter_idx; unsigned int depth; int state; uint32_t key; EFSYS_ASSERT3P(spec, !=, NULL); if ((rc = falconsiena_filter_spec_from_gen_spec(&fs_spec, spec)) != 0) goto fail1; tbl_id = falconsiena_filter_tbl_id(fs_spec.fsfs_type); fsftp = &fsfp->fsf_tbl[tbl_id]; if (fsftp->fsft_size == 0) { rc = EINVAL; goto fail2; } key = falconsiena_filter_build(&filter, &fs_spec); EFSYS_LOCK(enp->en_eslp, state); rc = falconsiena_filter_search(fsftp, &fs_spec, key, B_TRUE, &filter_idx, &depth); if (rc != 0) goto fail3; EFSYS_ASSERT3U(filter_idx, <, fsftp->fsft_size); saved_fs_spec = &fsftp->fsft_spec[filter_idx]; if (falconsiena_filter_test_used(fsftp, filter_idx)) { if (may_replace == B_FALSE) { rc = EEXIST; goto fail4; } } falconsiena_filter_set_used(fsftp, filter_idx); *saved_fs_spec = fs_spec; if (fsfp->fsf_depth[fs_spec.fsfs_type] < depth) { fsfp->fsf_depth[fs_spec.fsfs_type] = depth; if (tbl_id == EFX_FS_FILTER_TBL_TX_IP || tbl_id == EFX_FS_FILTER_TBL_TX_MAC) falconsiena_filter_push_tx_limits(enp); else falconsiena_filter_push_rx_limits(enp); } falconsiena_filter_push_entry(enp, fs_spec.fsfs_type, filter_idx, &filter); EFSYS_UNLOCK(enp->en_eslp, state); return (0); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_UNLOCK(enp->en_eslp, state); EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t falconsiena_filter_delete( __in efx_nic_t *enp, __inout efx_filter_spec_t *spec) { efx_rc_t rc; falconsiena_filter_spec_t fs_spec; falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; falconsiena_filter_tbl_id_t tbl_id; falconsiena_filter_tbl_t *fsftp; efx_oword_t filter; int filter_idx; unsigned int depth; int state; uint32_t key; EFSYS_ASSERT3P(spec, !=, NULL); if ((rc = falconsiena_filter_spec_from_gen_spec(&fs_spec, spec)) != 0) goto fail1; tbl_id = falconsiena_filter_tbl_id(fs_spec.fsfs_type); fsftp = &fsfp->fsf_tbl[tbl_id]; key = falconsiena_filter_build(&filter, &fs_spec); EFSYS_LOCK(enp->en_eslp, state); rc = falconsiena_filter_search(fsftp, &fs_spec, key, B_FALSE, &filter_idx, &depth); if (rc != 0) goto fail2; falconsiena_filter_clear_entry(enp, fsftp, filter_idx); if (fsftp->fsft_used == 0) falconsiena_filter_reset_search_depth(fsfp, tbl_id); EFSYS_UNLOCK(enp->en_eslp, state); return (0); fail2: EFSYS_UNLOCK(enp->en_eslp, state); EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #define MAX_SUPPORTED 4 static __checkReturn efx_rc_t falconsiena_filter_supported_filters( __in efx_nic_t *enp, __out uint32_t *list, __out size_t *length) { int index = 0; uint32_t rx_matches[MAX_SUPPORTED]; efx_rc_t rc; if (list == NULL) { rc = EINVAL; goto fail1; } rx_matches[index++] = EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; rx_matches[index++] = EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) { rx_matches[index++] = EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC; rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC; } EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED); *length = index; memcpy(list, rx_matches, *length); return (0); fail1: return (rc); } #undef MAX_SUPPORTED #endif /* EFSYS_OPT_SIENA */ #endif /* EFSYS_OPT_FILTER */ Index: head/sys/dev/sfxge/common/efx_impl.h =================================================================== --- head/sys/dev/sfxge/common/efx_impl.h (revision 299516) +++ head/sys/dev/sfxge/common/efx_impl.h (revision 299517) @@ -1,1168 +1,1168 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. * * $FreeBSD$ */ #ifndef _SYS_EFX_IMPL_H #define _SYS_EFX_IMPL_H #include "efx.h" #include "efx_regs.h" #include "efx_regs_ef10.h" /* FIXME: Add definition for driver generated software events */ #ifndef ESE_DZ_EV_CODE_DRV_GEN_EV #define ESE_DZ_EV_CODE_DRV_GEN_EV FSE_AZ_EV_CODE_DRV_GEN_EV #endif #if EFSYS_OPT_SIENA #include "siena_impl.h" #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON #include "hunt_impl.h" #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD #include "medford_impl.h" #endif /* EFSYS_OPT_MEDFORD */ #if (EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) #include "ef10_impl.h" #endif /* (EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) */ #ifdef __cplusplus extern "C" { #endif #define EFX_MOD_MCDI 0x00000001 #define EFX_MOD_PROBE 0x00000002 #define EFX_MOD_NVRAM 0x00000004 #define EFX_MOD_VPD 0x00000008 #define EFX_MOD_NIC 0x00000010 #define EFX_MOD_INTR 0x00000020 #define EFX_MOD_EV 0x00000040 #define EFX_MOD_RX 0x00000080 #define EFX_MOD_TX 0x00000100 #define EFX_MOD_PORT 0x00000200 #define EFX_MOD_MON 0x00000400 #define EFX_MOD_WOL 0x00000800 #define EFX_MOD_FILTER 0x00001000 #define EFX_MOD_LIC 0x00002000 #define EFX_RESET_MAC 0x00000001 #define EFX_RESET_PHY 0x00000002 #define EFX_RESET_RXQ_ERR 0x00000004 #define EFX_RESET_TXQ_ERR 0x00000008 typedef enum efx_mac_type_e { EFX_MAC_INVALID = 0, EFX_MAC_SIENA, EFX_MAC_HUNTINGTON, EFX_MAC_MEDFORD, EFX_MAC_NTYPES } efx_mac_type_t; typedef struct efx_ev_ops_s { efx_rc_t (*eevo_init)(efx_nic_t *); void (*eevo_fini)(efx_nic_t *); efx_rc_t (*eevo_qcreate)(efx_nic_t *, unsigned int, efsys_mem_t *, size_t, uint32_t, efx_evq_t *); void (*eevo_qdestroy)(efx_evq_t *); efx_rc_t (*eevo_qprime)(efx_evq_t *, unsigned int); void (*eevo_qpost)(efx_evq_t *, uint16_t); efx_rc_t (*eevo_qmoderate)(efx_evq_t *, unsigned int); #if EFSYS_OPT_QSTATS void (*eevo_qstats_update)(efx_evq_t *, efsys_stat_t *); #endif } efx_ev_ops_t; typedef struct efx_tx_ops_s { efx_rc_t (*etxo_init)(efx_nic_t *); void (*etxo_fini)(efx_nic_t *); efx_rc_t (*etxo_qcreate)(efx_nic_t *, unsigned int, unsigned int, efsys_mem_t *, size_t, uint32_t, uint16_t, efx_evq_t *, efx_txq_t *, unsigned int *); void (*etxo_qdestroy)(efx_txq_t *); efx_rc_t (*etxo_qpost)(efx_txq_t *, efx_buffer_t *, unsigned int, unsigned int, unsigned int *); void (*etxo_qpush)(efx_txq_t *, unsigned int, unsigned int); efx_rc_t (*etxo_qpace)(efx_txq_t *, unsigned int); efx_rc_t (*etxo_qflush)(efx_txq_t *); void (*etxo_qenable)(efx_txq_t *); efx_rc_t (*etxo_qpio_enable)(efx_txq_t *); void (*etxo_qpio_disable)(efx_txq_t *); efx_rc_t (*etxo_qpio_write)(efx_txq_t *,uint8_t *, size_t, size_t); efx_rc_t (*etxo_qpio_post)(efx_txq_t *, size_t, unsigned int, unsigned int *); efx_rc_t (*etxo_qdesc_post)(efx_txq_t *, efx_desc_t *, unsigned int, unsigned int, unsigned int *); void (*etxo_qdesc_dma_create)(efx_txq_t *, efsys_dma_addr_t, size_t, boolean_t, efx_desc_t *); void (*etxo_qdesc_tso_create)(efx_txq_t *, uint16_t, uint32_t, uint8_t, efx_desc_t *); void (*etxo_qdesc_tso2_create)(efx_txq_t *, uint16_t, uint32_t, uint16_t, efx_desc_t *, int); void (*etxo_qdesc_vlantci_create)(efx_txq_t *, uint16_t, efx_desc_t *); #if EFSYS_OPT_QSTATS void (*etxo_qstats_update)(efx_txq_t *, efsys_stat_t *); #endif } efx_tx_ops_t; typedef struct efx_rx_ops_s { efx_rc_t (*erxo_init)(efx_nic_t *); void (*erxo_fini)(efx_nic_t *); #if EFSYS_OPT_RX_SCATTER efx_rc_t (*erxo_scatter_enable)(efx_nic_t *, unsigned int); #endif #if EFSYS_OPT_RX_SCALE efx_rc_t (*erxo_scale_mode_set)(efx_nic_t *, efx_rx_hash_alg_t, efx_rx_hash_type_t, boolean_t); efx_rc_t (*erxo_scale_key_set)(efx_nic_t *, uint8_t *, size_t); efx_rc_t (*erxo_scale_tbl_set)(efx_nic_t *, unsigned int *, size_t); uint32_t (*erxo_prefix_hash)(efx_nic_t *, efx_rx_hash_alg_t, uint8_t *); #endif /* EFSYS_OPT_RX_SCALE */ efx_rc_t (*erxo_prefix_pktlen)(efx_nic_t *, uint8_t *, uint16_t *); void (*erxo_qpost)(efx_rxq_t *, efsys_dma_addr_t *, size_t, unsigned int, unsigned int, unsigned int); void (*erxo_qpush)(efx_rxq_t *, unsigned int, unsigned int *); efx_rc_t (*erxo_qflush)(efx_rxq_t *); void (*erxo_qenable)(efx_rxq_t *); efx_rc_t (*erxo_qcreate)(efx_nic_t *enp, unsigned int, unsigned int, efx_rxq_type_t, efsys_mem_t *, size_t, uint32_t, efx_evq_t *, efx_rxq_t *); void (*erxo_qdestroy)(efx_rxq_t *); } efx_rx_ops_t; typedef struct efx_mac_ops_s { efx_rc_t (*emo_reset)(efx_nic_t *); /* optional */ efx_rc_t (*emo_poll)(efx_nic_t *, efx_link_mode_t *); efx_rc_t (*emo_up)(efx_nic_t *, boolean_t *); efx_rc_t (*emo_addr_set)(efx_nic_t *); efx_rc_t (*emo_pdu_set)(efx_nic_t *); efx_rc_t (*emo_reconfigure)(efx_nic_t *); efx_rc_t (*emo_multicast_list_set)(efx_nic_t *); efx_rc_t (*emo_filter_default_rxq_set)(efx_nic_t *, efx_rxq_t *, boolean_t); void (*emo_filter_default_rxq_clear)(efx_nic_t *); #if EFSYS_OPT_LOOPBACK efx_rc_t (*emo_loopback_set)(efx_nic_t *, efx_link_mode_t, efx_loopback_type_t); #endif /* EFSYS_OPT_LOOPBACK */ #if EFSYS_OPT_MAC_STATS efx_rc_t (*emo_stats_upload)(efx_nic_t *, efsys_mem_t *); efx_rc_t (*emo_stats_periodic)(efx_nic_t *, efsys_mem_t *, uint16_t, boolean_t); efx_rc_t (*emo_stats_update)(efx_nic_t *, efsys_mem_t *, efsys_stat_t *, uint32_t *); #endif /* EFSYS_OPT_MAC_STATS */ } efx_mac_ops_t; typedef struct efx_phy_ops_s { efx_rc_t (*epo_power)(efx_nic_t *, boolean_t); /* optional */ efx_rc_t (*epo_reset)(efx_nic_t *); efx_rc_t (*epo_reconfigure)(efx_nic_t *); efx_rc_t (*epo_verify)(efx_nic_t *); efx_rc_t (*epo_uplink_check)(efx_nic_t *, boolean_t *); /* optional */ efx_rc_t (*epo_downlink_check)(efx_nic_t *, efx_link_mode_t *, unsigned int *, uint32_t *); efx_rc_t (*epo_oui_get)(efx_nic_t *, uint32_t *); #if EFSYS_OPT_PHY_STATS efx_rc_t (*epo_stats_update)(efx_nic_t *, efsys_mem_t *, uint32_t *); #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_PHY_PROPS #if EFSYS_OPT_NAMES const char *(*epo_prop_name)(efx_nic_t *, unsigned int); #endif /* EFSYS_OPT_PHY_PROPS */ efx_rc_t (*epo_prop_get)(efx_nic_t *, unsigned int, uint32_t, uint32_t *); efx_rc_t (*epo_prop_set)(efx_nic_t *, unsigned int, uint32_t); #endif /* EFSYS_OPT_PHY_PROPS */ #if EFSYS_OPT_BIST efx_rc_t (*epo_bist_enable_offline)(efx_nic_t *); efx_rc_t (*epo_bist_start)(efx_nic_t *, efx_bist_type_t); efx_rc_t (*epo_bist_poll)(efx_nic_t *, efx_bist_type_t, efx_bist_result_t *, uint32_t *, unsigned long *, size_t); void (*epo_bist_stop)(efx_nic_t *, efx_bist_type_t); #endif /* EFSYS_OPT_BIST */ } efx_phy_ops_t; #if EFSYS_OPT_FILTER typedef struct efx_filter_ops_s { efx_rc_t (*efo_init)(efx_nic_t *); void (*efo_fini)(efx_nic_t *); efx_rc_t (*efo_restore)(efx_nic_t *); efx_rc_t (*efo_add)(efx_nic_t *, efx_filter_spec_t *, boolean_t may_replace); efx_rc_t (*efo_delete)(efx_nic_t *, efx_filter_spec_t *); efx_rc_t (*efo_supported_filters)(efx_nic_t *, uint32_t *, size_t *); efx_rc_t (*efo_reconfigure)(efx_nic_t *, uint8_t const *, boolean_t, boolean_t, boolean_t, boolean_t, uint8_t const *, uint32_t); } efx_filter_ops_t; extern __checkReturn efx_rc_t efx_filter_reconfigure( __in efx_nic_t *enp, __in_ecount(6) uint8_t const *mac_addr, __in boolean_t all_unicst, __in boolean_t mulcst, __in boolean_t all_mulcst, __in boolean_t brdcst, __in_ecount(6*count) uint8_t const *addrs, __in uint32_t count); #endif /* EFSYS_OPT_FILTER */ typedef struct efx_port_s { efx_mac_type_t ep_mac_type; uint32_t ep_phy_type; uint8_t ep_port; uint32_t ep_mac_pdu; uint8_t ep_mac_addr[6]; efx_link_mode_t ep_link_mode; boolean_t ep_all_unicst; boolean_t ep_mulcst; boolean_t ep_all_mulcst; boolean_t ep_brdcst; unsigned int ep_fcntl; boolean_t ep_fcntl_autoneg; efx_oword_t ep_multicst_hash[2]; uint8_t ep_mulcst_addr_list[EFX_MAC_ADDR_LEN * EFX_MAC_MULTICAST_LIST_MAX]; uint32_t ep_mulcst_addr_count; #if EFSYS_OPT_LOOPBACK efx_loopback_type_t ep_loopback_type; efx_link_mode_t ep_loopback_link_mode; #endif /* EFSYS_OPT_LOOPBACK */ #if EFSYS_OPT_PHY_FLAGS uint32_t ep_phy_flags; #endif /* EFSYS_OPT_PHY_FLAGS */ #if EFSYS_OPT_PHY_LED_CONTROL efx_phy_led_mode_t ep_phy_led_mode; #endif /* EFSYS_OPT_PHY_LED_CONTROL */ efx_phy_media_type_t ep_fixed_port_type; efx_phy_media_type_t ep_module_type; uint32_t ep_adv_cap_mask; uint32_t ep_lp_cap_mask; uint32_t ep_default_adv_cap_mask; uint32_t ep_phy_cap_mask; boolean_t ep_mac_drain; boolean_t ep_mac_stats_pending; #if EFSYS_OPT_BIST efx_bist_type_t ep_current_bist; #endif - efx_mac_ops_t *ep_emop; - efx_phy_ops_t *ep_epop; + const efx_mac_ops_t *ep_emop; + const efx_phy_ops_t *ep_epop; } efx_port_t; typedef struct efx_mon_ops_s { efx_rc_t (*emo_reset)(efx_nic_t *); efx_rc_t (*emo_reconfigure)(efx_nic_t *); #if EFSYS_OPT_MON_STATS efx_rc_t (*emo_stats_update)(efx_nic_t *, efsys_mem_t *, efx_mon_stat_value_t *); #endif /* EFSYS_OPT_MON_STATS */ } efx_mon_ops_t; typedef struct efx_mon_s { - efx_mon_type_t em_type; - efx_mon_ops_t *em_emop; + efx_mon_type_t em_type; + const efx_mon_ops_t *em_emop; } efx_mon_t; typedef struct efx_intr_ops_s { efx_rc_t (*eio_init)(efx_nic_t *, efx_intr_type_t, efsys_mem_t *); void (*eio_enable)(efx_nic_t *); void (*eio_disable)(efx_nic_t *); void (*eio_disable_unlocked)(efx_nic_t *); efx_rc_t (*eio_trigger)(efx_nic_t *, unsigned int); void (*eio_status_line)(efx_nic_t *, boolean_t *, uint32_t *); void (*eio_status_message)(efx_nic_t *, unsigned int, boolean_t *); void (*eio_fatal)(efx_nic_t *); void (*eio_fini)(efx_nic_t *); } efx_intr_ops_t; typedef struct efx_intr_s { - efx_intr_ops_t *ei_eiop; - efsys_mem_t *ei_esmp; - efx_intr_type_t ei_type; - unsigned int ei_level; + const efx_intr_ops_t *ei_eiop; + efsys_mem_t *ei_esmp; + efx_intr_type_t ei_type; + unsigned int ei_level; } efx_intr_t; typedef struct efx_nic_ops_s { efx_rc_t (*eno_probe)(efx_nic_t *); efx_rc_t (*eno_board_cfg)(efx_nic_t *); efx_rc_t (*eno_set_drv_limits)(efx_nic_t *, efx_drv_limits_t*); efx_rc_t (*eno_reset)(efx_nic_t *); efx_rc_t (*eno_init)(efx_nic_t *); efx_rc_t (*eno_get_vi_pool)(efx_nic_t *, uint32_t *); efx_rc_t (*eno_get_bar_region)(efx_nic_t *, efx_nic_region_t, uint32_t *, size_t *); #if EFSYS_OPT_DIAG efx_rc_t (*eno_register_test)(efx_nic_t *); #endif /* EFSYS_OPT_DIAG */ void (*eno_fini)(efx_nic_t *); void (*eno_unprobe)(efx_nic_t *); } efx_nic_ops_t; #ifndef EFX_TXQ_LIMIT_TARGET #define EFX_TXQ_LIMIT_TARGET 259 #endif #ifndef EFX_RXQ_LIMIT_TARGET #define EFX_RXQ_LIMIT_TARGET 512 #endif #ifndef EFX_TXQ_DC_SIZE #define EFX_TXQ_DC_SIZE 1 /* 16 descriptors */ #endif #ifndef EFX_RXQ_DC_SIZE #define EFX_RXQ_DC_SIZE 3 /* 64 descriptors */ #endif #if EFSYS_OPT_FILTER typedef struct falconsiena_filter_spec_s { uint8_t fsfs_type; uint32_t fsfs_flags; uint32_t fsfs_dmaq_id; uint32_t fsfs_dword[3]; } falconsiena_filter_spec_t; typedef enum falconsiena_filter_type_e { EFX_FS_FILTER_RX_TCP_FULL, /* TCP/IPv4 4-tuple {dIP,dTCP,sIP,sTCP} */ EFX_FS_FILTER_RX_TCP_WILD, /* TCP/IPv4 dest {dIP,dTCP, -, -} */ EFX_FS_FILTER_RX_UDP_FULL, /* UDP/IPv4 4-tuple {dIP,dUDP,sIP,sUDP} */ EFX_FS_FILTER_RX_UDP_WILD, /* UDP/IPv4 dest {dIP,dUDP, -, -} */ #if EFSYS_OPT_SIENA EFX_FS_FILTER_RX_MAC_FULL, /* Ethernet {dMAC,VLAN} */ EFX_FS_FILTER_RX_MAC_WILD, /* Ethernet {dMAC, -} */ EFX_FS_FILTER_TX_TCP_FULL, /* TCP/IPv4 {dIP,dTCP,sIP,sTCP} */ EFX_FS_FILTER_TX_TCP_WILD, /* TCP/IPv4 { -, -,sIP,sTCP} */ EFX_FS_FILTER_TX_UDP_FULL, /* UDP/IPv4 {dIP,dTCP,sIP,sTCP} */ EFX_FS_FILTER_TX_UDP_WILD, /* UDP/IPv4 source (host, port) */ EFX_FS_FILTER_TX_MAC_FULL, /* Ethernet source (MAC address, VLAN ID) */ EFX_FS_FILTER_TX_MAC_WILD, /* Ethernet source (MAC address) */ #endif /* EFSYS_OPT_SIENA */ EFX_FS_FILTER_NTYPES } falconsiena_filter_type_t; typedef enum falconsiena_filter_tbl_id_e { EFX_FS_FILTER_TBL_RX_IP = 0, EFX_FS_FILTER_TBL_RX_MAC, EFX_FS_FILTER_TBL_TX_IP, EFX_FS_FILTER_TBL_TX_MAC, EFX_FS_FILTER_NTBLS } falconsiena_filter_tbl_id_t; typedef struct falconsiena_filter_tbl_s { int fsft_size; /* number of entries */ int fsft_used; /* active count */ uint32_t *fsft_bitmap; /* active bitmap */ falconsiena_filter_spec_t *fsft_spec; /* array of saved specs */ } falconsiena_filter_tbl_t; typedef struct falconsiena_filter_s { falconsiena_filter_tbl_t fsf_tbl[EFX_FS_FILTER_NTBLS]; unsigned int fsf_depth[EFX_FS_FILTER_NTYPES]; } falconsiena_filter_t; typedef struct efx_filter_s { #if EFSYS_OPT_SIENA falconsiena_filter_t *ef_falconsiena_filter; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD ef10_filter_table_t *ef_ef10_filter_table; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ } efx_filter_t; extern void falconsiena_filter_tbl_clear( __in efx_nic_t *enp, __in falconsiena_filter_tbl_id_t tbl); #endif /* EFSYS_OPT_FILTER */ #if EFSYS_OPT_MCDI typedef struct efx_mcdi_ops_s { efx_rc_t (*emco_init)(efx_nic_t *, const efx_mcdi_transport_t *); void (*emco_send_request)(efx_nic_t *, void *, size_t, void *, size_t); efx_rc_t (*emco_poll_reboot)(efx_nic_t *); boolean_t (*emco_poll_response)(efx_nic_t *); void (*emco_read_response)(efx_nic_t *, void *, size_t, size_t); void (*emco_fini)(efx_nic_t *); efx_rc_t (*emco_feature_supported)(efx_nic_t *, efx_mcdi_feature_id_t, boolean_t *); } efx_mcdi_ops_t; typedef struct efx_mcdi_s { - efx_mcdi_ops_t *em_emcop; + const efx_mcdi_ops_t *em_emcop; const efx_mcdi_transport_t *em_emtp; efx_mcdi_iface_t em_emip; } efx_mcdi_t; #endif /* EFSYS_OPT_MCDI */ #if EFSYS_OPT_NVRAM typedef struct efx_nvram_ops_s { #if EFSYS_OPT_DIAG efx_rc_t (*envo_test)(efx_nic_t *); #endif /* EFSYS_OPT_DIAG */ efx_rc_t (*envo_type_to_partn)(efx_nic_t *, efx_nvram_type_t, uint32_t *); efx_rc_t (*envo_partn_size)(efx_nic_t *, uint32_t, size_t *); efx_rc_t (*envo_partn_rw_start)(efx_nic_t *, uint32_t, size_t *); efx_rc_t (*envo_partn_read)(efx_nic_t *, uint32_t, unsigned int, caddr_t, size_t); efx_rc_t (*envo_partn_erase)(efx_nic_t *, uint32_t, unsigned int, size_t); efx_rc_t (*envo_partn_write)(efx_nic_t *, uint32_t, unsigned int, caddr_t, size_t); void (*envo_partn_rw_finish)(efx_nic_t *, uint32_t); efx_rc_t (*envo_partn_get_version)(efx_nic_t *, uint32_t, uint32_t *, uint16_t *); efx_rc_t (*envo_partn_set_version)(efx_nic_t *, uint32_t, uint16_t *); efx_rc_t (*envo_buffer_validate)(efx_nic_t *, uint32_t, caddr_t, size_t); } efx_nvram_ops_t; #endif /* EFSYS_OPT_NVRAM */ extern __checkReturn efx_rc_t efx_nvram_tlv_validate( __in efx_nic_t *enp, __in uint32_t partn, __in_bcount(partn_size) caddr_t partn_data, __in size_t partn_size); #if EFSYS_OPT_VPD typedef struct efx_vpd_ops_s { efx_rc_t (*evpdo_init)(efx_nic_t *); efx_rc_t (*evpdo_size)(efx_nic_t *, size_t *); efx_rc_t (*evpdo_read)(efx_nic_t *, caddr_t, size_t); efx_rc_t (*evpdo_verify)(efx_nic_t *, caddr_t, size_t); efx_rc_t (*evpdo_reinit)(efx_nic_t *, caddr_t, size_t); efx_rc_t (*evpdo_get)(efx_nic_t *, caddr_t, size_t, efx_vpd_value_t *); efx_rc_t (*evpdo_set)(efx_nic_t *, caddr_t, size_t, efx_vpd_value_t *); efx_rc_t (*evpdo_next)(efx_nic_t *, caddr_t, size_t, efx_vpd_value_t *, unsigned int *); efx_rc_t (*evpdo_write)(efx_nic_t *, caddr_t, size_t); void (*evpdo_fini)(efx_nic_t *); } efx_vpd_ops_t; #endif /* EFSYS_OPT_VPD */ #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM __checkReturn efx_rc_t efx_mcdi_nvram_partitions( __in efx_nic_t *enp, __out_bcount(size) caddr_t data, __in size_t size, __out unsigned int *npartnp); __checkReturn efx_rc_t efx_mcdi_nvram_metadata( __in efx_nic_t *enp, __in uint32_t partn, __out uint32_t *subtypep, __out_ecount(4) uint16_t version[4], __out_bcount_opt(size) char *descp, __in size_t size); __checkReturn efx_rc_t efx_mcdi_nvram_info( __in efx_nic_t *enp, __in uint32_t partn, __out_opt size_t *sizep, __out_opt uint32_t *addressp, __out_opt uint32_t *erase_sizep, __out_opt uint32_t *write_sizep); __checkReturn efx_rc_t efx_mcdi_nvram_update_start( __in efx_nic_t *enp, __in uint32_t partn); __checkReturn efx_rc_t efx_mcdi_nvram_read( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t offset, __out_bcount(size) caddr_t data, __in size_t size, __in uint32_t mode); __checkReturn efx_rc_t efx_mcdi_nvram_erase( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t offset, __in size_t size); __checkReturn efx_rc_t efx_mcdi_nvram_write( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t offset, __out_bcount(size) caddr_t data, __in size_t size); __checkReturn efx_rc_t efx_mcdi_nvram_update_finish( __in efx_nic_t *enp, __in uint32_t partn, __in boolean_t reboot); #if EFSYS_OPT_DIAG __checkReturn efx_rc_t efx_mcdi_nvram_test( __in efx_nic_t *enp, __in uint32_t partn); #endif /* EFSYS_OPT_DIAG */ #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ #if EFSYS_OPT_LICENSING typedef struct efx_lic_ops_s { efx_rc_t (*elo_update_licenses)(efx_nic_t *); efx_rc_t (*elo_get_key_stats)(efx_nic_t *, efx_key_stats_t *); efx_rc_t (*elo_app_state)(efx_nic_t *, uint64_t, boolean_t *); efx_rc_t (*elo_get_id)(efx_nic_t *, size_t, uint32_t *, size_t *, uint8_t *); } efx_lic_ops_t; #endif typedef struct efx_drv_cfg_s { uint32_t edc_min_vi_count; uint32_t edc_max_vi_count; uint32_t edc_max_piobuf_count; uint32_t edc_pio_alloc_size; } efx_drv_cfg_t; struct efx_nic_s { uint32_t en_magic; efx_family_t en_family; uint32_t en_features; efsys_identifier_t *en_esip; efsys_lock_t *en_eslp; efsys_bar_t *en_esbp; unsigned int en_mod_flags; unsigned int en_reset_flags; efx_nic_cfg_t en_nic_cfg; efx_drv_cfg_t en_drv_cfg; efx_port_t en_port; efx_mon_t en_mon; efx_intr_t en_intr; uint32_t en_ev_qcount; uint32_t en_rx_qcount; uint32_t en_tx_qcount; - efx_nic_ops_t *en_enop; - efx_ev_ops_t *en_eevop; - efx_tx_ops_t *en_etxop; - efx_rx_ops_t *en_erxop; + const efx_nic_ops_t *en_enop; + const efx_ev_ops_t *en_eevop; + const efx_tx_ops_t *en_etxop; + const efx_rx_ops_t *en_erxop; #if EFSYS_OPT_FILTER efx_filter_t en_filter; - efx_filter_ops_t *en_efop; + const efx_filter_ops_t *en_efop; #endif /* EFSYS_OPT_FILTER */ #if EFSYS_OPT_MCDI efx_mcdi_t en_mcdi; #endif /* EFSYS_OPT_MCDI */ #if EFSYS_OPT_NVRAM efx_nvram_type_t en_nvram_locked; - efx_nvram_ops_t *en_envop; + const efx_nvram_ops_t *en_envop; #endif /* EFSYS_OPT_NVRAM */ #if EFSYS_OPT_VPD - efx_vpd_ops_t *en_evpdop; + const efx_vpd_ops_t *en_evpdop; #endif /* EFSYS_OPT_VPD */ #if EFSYS_OPT_RX_SCALE efx_rx_hash_support_t en_hash_support; efx_rx_scale_support_t en_rss_support; uint32_t en_rss_context; #endif /* EFSYS_OPT_RX_SCALE */ uint32_t en_vport_id; #if EFSYS_OPT_LICENSING - efx_lic_ops_t *en_elop; + const efx_lic_ops_t *en_elop; #endif union { #if EFSYS_OPT_SIENA struct { #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD unsigned int enu_partn_mask; #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ #if EFSYS_OPT_VPD caddr_t enu_svpd; size_t enu_svpd_length; #endif /* EFSYS_OPT_VPD */ int enu_unused; } siena; #endif /* EFSYS_OPT_SIENA */ int enu_unused; } en_u; #if (EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) union en_arch { struct { int ena_vi_base; int ena_vi_count; int ena_vi_shift; #if EFSYS_OPT_VPD caddr_t ena_svpd; size_t ena_svpd_length; #endif /* EFSYS_OPT_VPD */ efx_piobuf_handle_t ena_piobuf_handle[EF10_MAX_PIOBUF_NBUFS]; uint32_t ena_piobuf_count; uint32_t ena_pio_alloc_map[EF10_MAX_PIOBUF_NBUFS]; uint32_t ena_pio_write_vi_base; /* Memory BAR mapping regions */ uint32_t ena_uc_mem_map_offset; size_t ena_uc_mem_map_size; uint32_t ena_wc_mem_map_offset; size_t ena_wc_mem_map_size; } ef10; } en_arch; #endif /* (EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) */ }; #define EFX_NIC_MAGIC 0x02121996 typedef boolean_t (*efx_ev_handler_t)(efx_evq_t *, efx_qword_t *, const efx_ev_callbacks_t *, void *); typedef struct efx_evq_rxq_state_s { unsigned int eers_rx_read_ptr; unsigned int eers_rx_mask; } efx_evq_rxq_state_t; struct efx_evq_s { uint32_t ee_magic; efx_nic_t *ee_enp; unsigned int ee_index; unsigned int ee_mask; efsys_mem_t *ee_esmp; #if EFSYS_OPT_QSTATS uint32_t ee_stat[EV_NQSTATS]; #endif /* EFSYS_OPT_QSTATS */ efx_ev_handler_t ee_rx; efx_ev_handler_t ee_tx; efx_ev_handler_t ee_driver; efx_ev_handler_t ee_global; efx_ev_handler_t ee_drv_gen; #if EFSYS_OPT_MCDI efx_ev_handler_t ee_mcdi; #endif /* EFSYS_OPT_MCDI */ efx_evq_rxq_state_t ee_rxq_state[EFX_EV_RX_NLABELS]; }; #define EFX_EVQ_MAGIC 0x08081997 #define EFX_EVQ_FALCON_TIMER_QUANTUM_NS 4968 /* 621 cycles */ #define EFX_EVQ_SIENA_TIMER_QUANTUM_NS 6144 /* 768 cycles */ struct efx_rxq_s { uint32_t er_magic; efx_nic_t *er_enp; efx_evq_t *er_eep; unsigned int er_index; unsigned int er_label; unsigned int er_mask; efsys_mem_t *er_esmp; }; #define EFX_RXQ_MAGIC 0x15022005 struct efx_txq_s { uint32_t et_magic; efx_nic_t *et_enp; unsigned int et_index; unsigned int et_mask; efsys_mem_t *et_esmp; #if EFSYS_OPT_HUNTINGTON uint32_t et_pio_bufnum; uint32_t et_pio_blknum; uint32_t et_pio_write_offset; uint32_t et_pio_offset; size_t et_pio_size; #endif #if EFSYS_OPT_QSTATS uint32_t et_stat[TX_NQSTATS]; #endif /* EFSYS_OPT_QSTATS */ }; #define EFX_TXQ_MAGIC 0x05092005 #define EFX_MAC_ADDR_COPY(_dst, _src) \ do { \ (_dst)[0] = (_src)[0]; \ (_dst)[1] = (_src)[1]; \ (_dst)[2] = (_src)[2]; \ (_dst)[3] = (_src)[3]; \ (_dst)[4] = (_src)[4]; \ (_dst)[5] = (_src)[5]; \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_MAC_BROADCAST_ADDR_SET(_dst) \ do { \ uint16_t *_d = (uint16_t *)(_dst); \ _d[0] = 0xffff; \ _d[1] = 0xffff; \ _d[2] = 0xffff; \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #if EFSYS_OPT_CHECK_REG #define EFX_CHECK_REG(_enp, _reg) \ do { \ const char *name = #_reg; \ char min = name[4]; \ char max = name[5]; \ char rev; \ \ switch ((_enp)->en_family) { \ case EFX_FAMILY_SIENA: \ rev = 'C'; \ break; \ \ case EFX_FAMILY_HUNTINGTON: \ rev = 'D'; \ break; \ \ case EFX_FAMILY_MEDFORD: \ rev = 'E'; \ break; \ \ default: \ rev = '?'; \ break; \ } \ \ EFSYS_ASSERT3S(rev, >=, min); \ EFSYS_ASSERT3S(rev, <=, max); \ \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #else #define EFX_CHECK_REG(_enp, _reg) do { \ _NOTE(CONSTANTCONDITION) \ } while(B_FALSE) #endif #define EFX_BAR_READD(_enp, _reg, _edp, _lock) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_BAR_READD((_enp)->en_esbp, _reg ## _OFST, \ (_edp), (_lock)); \ EFSYS_PROBE3(efx_bar_readd, const char *, #_reg, \ uint32_t, _reg ## _OFST, \ uint32_t, (_edp)->ed_u32[0]); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_WRITED(_enp, _reg, _edp, _lock) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE3(efx_bar_writed, const char *, #_reg, \ uint32_t, _reg ## _OFST, \ uint32_t, (_edp)->ed_u32[0]); \ EFSYS_BAR_WRITED((_enp)->en_esbp, _reg ## _OFST, \ (_edp), (_lock)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_READQ(_enp, _reg, _eqp) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_BAR_READQ((_enp)->en_esbp, _reg ## _OFST, \ (_eqp)); \ EFSYS_PROBE4(efx_bar_readq, const char *, #_reg, \ uint32_t, _reg ## _OFST, \ uint32_t, (_eqp)->eq_u32[1], \ uint32_t, (_eqp)->eq_u32[0]); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_WRITEQ(_enp, _reg, _eqp) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE4(efx_bar_writeq, const char *, #_reg, \ uint32_t, _reg ## _OFST, \ uint32_t, (_eqp)->eq_u32[1], \ uint32_t, (_eqp)->eq_u32[0]); \ EFSYS_BAR_WRITEQ((_enp)->en_esbp, _reg ## _OFST, \ (_eqp)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_READO(_enp, _reg, _eop) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_BAR_READO((_enp)->en_esbp, _reg ## _OFST, \ (_eop), B_TRUE); \ EFSYS_PROBE6(efx_bar_reado, const char *, #_reg, \ uint32_t, _reg ## _OFST, \ uint32_t, (_eop)->eo_u32[3], \ uint32_t, (_eop)->eo_u32[2], \ uint32_t, (_eop)->eo_u32[1], \ uint32_t, (_eop)->eo_u32[0]); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_WRITEO(_enp, _reg, _eop) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE6(efx_bar_writeo, const char *, #_reg, \ uint32_t, _reg ## _OFST, \ uint32_t, (_eop)->eo_u32[3], \ uint32_t, (_eop)->eo_u32[2], \ uint32_t, (_eop)->eo_u32[1], \ uint32_t, (_eop)->eo_u32[0]); \ EFSYS_BAR_WRITEO((_enp)->en_esbp, _reg ## _OFST, \ (_eop), B_TRUE); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_TBL_READD(_enp, _reg, _index, _edp, _lock) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_BAR_READD((_enp)->en_esbp, \ (_reg ## _OFST + ((_index) * _reg ## _STEP)), \ (_edp), (_lock)); \ EFSYS_PROBE4(efx_bar_tbl_readd, const char *, #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_edp)->ed_u32[0]); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_TBL_WRITED(_enp, _reg, _index, _edp, _lock) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE4(efx_bar_tbl_writed, const char *, #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_edp)->ed_u32[0]); \ EFSYS_BAR_WRITED((_enp)->en_esbp, \ (_reg ## _OFST + ((_index) * _reg ## _STEP)), \ (_edp), (_lock)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_TBL_WRITED2(_enp, _reg, _index, _edp, _lock) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE4(efx_bar_tbl_writed, const char *, #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_edp)->ed_u32[0]); \ EFSYS_BAR_WRITED((_enp)->en_esbp, \ (_reg ## _OFST + \ (2 * sizeof (efx_dword_t)) + \ ((_index) * _reg ## _STEP)), \ (_edp), (_lock)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_TBL_WRITED3(_enp, _reg, _index, _edp, _lock) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE4(efx_bar_tbl_writed, const char *, #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_edp)->ed_u32[0]); \ EFSYS_BAR_WRITED((_enp)->en_esbp, \ (_reg ## _OFST + \ (3 * sizeof (efx_dword_t)) + \ ((_index) * _reg ## _STEP)), \ (_edp), (_lock)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_TBL_READQ(_enp, _reg, _index, _eqp) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_BAR_READQ((_enp)->en_esbp, \ (_reg ## _OFST + ((_index) * _reg ## _STEP)), \ (_eqp)); \ EFSYS_PROBE5(efx_bar_tbl_readq, const char *, #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_eqp)->eq_u32[1], \ uint32_t, (_eqp)->eq_u32[0]); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_TBL_WRITEQ(_enp, _reg, _index, _eqp) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE5(efx_bar_tbl_writeq, const char *, #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_eqp)->eq_u32[1], \ uint32_t, (_eqp)->eq_u32[0]); \ EFSYS_BAR_WRITEQ((_enp)->en_esbp, \ (_reg ## _OFST + ((_index) * _reg ## _STEP)), \ (_eqp)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_TBL_READO(_enp, _reg, _index, _eop, _lock) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_BAR_READO((_enp)->en_esbp, \ (_reg ## _OFST + ((_index) * _reg ## _STEP)), \ (_eop), (_lock)); \ EFSYS_PROBE7(efx_bar_tbl_reado, const char *, #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_eop)->eo_u32[3], \ uint32_t, (_eop)->eo_u32[2], \ uint32_t, (_eop)->eo_u32[1], \ uint32_t, (_eop)->eo_u32[0]); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_BAR_TBL_WRITEO(_enp, _reg, _index, _eop, _lock) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE7(efx_bar_tbl_writeo, const char *, #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_eop)->eo_u32[3], \ uint32_t, (_eop)->eo_u32[2], \ uint32_t, (_eop)->eo_u32[1], \ uint32_t, (_eop)->eo_u32[0]); \ EFSYS_BAR_WRITEO((_enp)->en_esbp, \ (_reg ## _OFST + ((_index) * _reg ## _STEP)), \ (_eop), (_lock)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) /* * Allow drivers to perform optimised 128-bit doorbell writes. * The DMA descriptor pointers (RX_DESC_UPD and TX_DESC_UPD) are * special-cased in the BIU on the Falcon/Siena and EF10 architectures to avoid * the need for locking in the host, and are the only ones known to be safe to * use 128-bites write with. */ #define EFX_BAR_TBL_DOORBELL_WRITEO(_enp, _reg, _index, _eop) \ do { \ EFX_CHECK_REG((_enp), (_reg)); \ EFSYS_PROBE7(efx_bar_tbl_doorbell_writeo, \ const char *, \ #_reg, \ uint32_t, (_index), \ uint32_t, _reg ## _OFST, \ uint32_t, (_eop)->eo_u32[3], \ uint32_t, (_eop)->eo_u32[2], \ uint32_t, (_eop)->eo_u32[1], \ uint32_t, (_eop)->eo_u32[0]); \ EFSYS_BAR_DOORBELL_WRITEO((_enp)->en_esbp, \ (_reg ## _OFST + ((_index) * _reg ## _STEP)), \ (_eop)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_DMA_SYNC_QUEUE_FOR_DEVICE(_esmp, _entries, _wptr, _owptr) \ do { \ unsigned int _new = (_wptr); \ unsigned int _old = (_owptr); \ \ if ((_new) >= (_old)) \ EFSYS_DMA_SYNC_FOR_DEVICE((_esmp), \ (_old) * sizeof (efx_desc_t), \ ((_new) - (_old)) * sizeof (efx_desc_t)); \ else \ /* \ * It is cheaper to sync entire map than sync \ * two parts especially when offset/size are \ * ignored and entire map is synced in any case.\ */ \ EFSYS_DMA_SYNC_FOR_DEVICE((_esmp), \ 0, \ (_entries) * sizeof (efx_desc_t)); \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) extern __checkReturn efx_rc_t efx_nic_biu_test( __in efx_nic_t *enp); extern __checkReturn efx_rc_t efx_mac_select( __in efx_nic_t *enp); extern void efx_mac_multicast_hash_compute( __in_ecount(6*count) uint8_t const *addrs, __in int count, __out efx_oword_t *hash_low, __out efx_oword_t *hash_high); extern __checkReturn efx_rc_t efx_phy_probe( __in efx_nic_t *enp); extern void efx_phy_unprobe( __in efx_nic_t *enp); #if EFSYS_OPT_VPD /* VPD utility functions */ extern __checkReturn efx_rc_t efx_vpd_hunk_length( __in_bcount(size) caddr_t data, __in size_t size, __out size_t *lengthp); extern __checkReturn efx_rc_t efx_vpd_hunk_verify( __in_bcount(size) caddr_t data, __in size_t size, __out_opt boolean_t *cksummedp); extern __checkReturn efx_rc_t efx_vpd_hunk_reinit( __in_bcount(size) caddr_t data, __in size_t size, __in boolean_t wantpid); extern __checkReturn efx_rc_t efx_vpd_hunk_get( __in_bcount(size) caddr_t data, __in size_t size, __in efx_vpd_tag_t tag, __in efx_vpd_keyword_t keyword, __out unsigned int *payloadp, __out uint8_t *paylenp); extern __checkReturn efx_rc_t efx_vpd_hunk_next( __in_bcount(size) caddr_t data, __in size_t size, __out efx_vpd_tag_t *tagp, __out efx_vpd_keyword_t *keyword, __out_opt unsigned int *payloadp, __out_opt uint8_t *paylenp, __inout unsigned int *contp); extern __checkReturn efx_rc_t efx_vpd_hunk_set( __in_bcount(size) caddr_t data, __in size_t size, __in efx_vpd_value_t *evvp); #endif /* EFSYS_OPT_VPD */ #if EFSYS_OPT_DIAG extern efx_sram_pattern_fn_t __efx_sram_pattern_fns[]; typedef struct efx_register_set_s { unsigned int address; unsigned int step; unsigned int rows; efx_oword_t mask; } efx_register_set_t; extern __checkReturn efx_rc_t efx_nic_test_registers( __in efx_nic_t *enp, __in efx_register_set_t *rsp, __in size_t count); extern __checkReturn efx_rc_t efx_nic_test_tables( __in efx_nic_t *enp, __in efx_register_set_t *rsp, __in efx_pattern_type_t pattern, __in size_t count); #endif /* EFSYS_OPT_DIAG */ #if EFSYS_OPT_MCDI extern __checkReturn efx_rc_t efx_mcdi_set_workaround( __in efx_nic_t *enp, __in uint32_t type, __in boolean_t enabled, __out_opt uint32_t *flagsp); extern __checkReturn efx_rc_t efx_mcdi_get_workarounds( __in efx_nic_t *enp, __out_opt uint32_t *implementedp, __out_opt uint32_t *enabledp); #endif /* EFSYS_OPT_MCDI */ #ifdef __cplusplus } #endif #endif /* _SYS_EFX_IMPL_H */ Index: head/sys/dev/sfxge/common/efx_intr.c =================================================================== --- head/sys/dev/sfxge/common/efx_intr.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_intr.c (revision 299517) @@ -1,575 +1,575 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_intr_init( __in efx_nic_t *enp, __in efx_intr_type_t type, __in efsys_mem_t *esmp); static void falconsiena_intr_enable( __in efx_nic_t *enp); static void falconsiena_intr_disable( __in efx_nic_t *enp); static void falconsiena_intr_disable_unlocked( __in efx_nic_t *enp); static __checkReturn efx_rc_t falconsiena_intr_trigger( __in efx_nic_t *enp, __in unsigned int level); static void falconsiena_intr_fini( __in efx_nic_t *enp); static void falconsiena_intr_status_line( __in efx_nic_t *enp, __out boolean_t *fatalp, __out uint32_t *qmaskp); static void falconsiena_intr_status_message( __in efx_nic_t *enp, __in unsigned int message, __out boolean_t *fatalp); static void falconsiena_intr_fatal( __in efx_nic_t *enp); static __checkReturn boolean_t falconsiena_intr_check_fatal( __in efx_nic_t *enp); #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_SIENA -static efx_intr_ops_t __efx_intr_siena_ops = { +static const efx_intr_ops_t __efx_intr_siena_ops = { falconsiena_intr_init, /* eio_init */ falconsiena_intr_enable, /* eio_enable */ falconsiena_intr_disable, /* eio_disable */ falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */ falconsiena_intr_trigger, /* eio_trigger */ falconsiena_intr_status_line, /* eio_status_line */ falconsiena_intr_status_message, /* eio_status_message */ falconsiena_intr_fatal, /* eio_fatal */ falconsiena_intr_fini, /* eio_fini */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_intr_ops_t __efx_intr_ef10_ops = { +static const efx_intr_ops_t __efx_intr_ef10_ops = { ef10_intr_init, /* eio_init */ ef10_intr_enable, /* eio_enable */ ef10_intr_disable, /* eio_disable */ ef10_intr_disable_unlocked, /* eio_disable_unlocked */ ef10_intr_trigger, /* eio_trigger */ ef10_intr_status_line, /* eio_status_line */ ef10_intr_status_message, /* eio_status_message */ ef10_intr_fatal, /* eio_fatal */ ef10_intr_fini, /* eio_fini */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_intr_init( __in efx_nic_t *enp, __in efx_intr_type_t type, __in efsys_mem_t *esmp) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop; + const efx_intr_ops_t *eiop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); if (enp->en_mod_flags & EFX_MOD_INTR) { rc = EINVAL; goto fail1; } eip->ei_esmp = esmp; eip->ei_type = type; eip->ei_level = 0; enp->en_mod_flags |= EFX_MOD_INTR; switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - eiop = (efx_intr_ops_t *)&__efx_intr_siena_ops; + eiop = &__efx_intr_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops; + eiop = &__efx_intr_ef10_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops; + eiop = &__efx_intr_ef10_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(B_FALSE); rc = ENOTSUP; goto fail2; } if ((rc = eiop->eio_init(enp, type, esmp)) != 0) goto fail3; eip->ei_eiop = eiop; return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_intr_fini( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop = eip->ei_eiop; + const efx_intr_ops_t *eiop = eip->ei_eiop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); eiop->eio_fini(enp); enp->en_mod_flags &= ~EFX_MOD_INTR; } void efx_intr_enable( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop = eip->ei_eiop; + const efx_intr_ops_t *eiop = eip->ei_eiop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); eiop->eio_enable(enp); } void efx_intr_disable( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop = eip->ei_eiop; + const efx_intr_ops_t *eiop = eip->ei_eiop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); eiop->eio_disable(enp); } void efx_intr_disable_unlocked( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop = eip->ei_eiop; + const efx_intr_ops_t *eiop = eip->ei_eiop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); eiop->eio_disable_unlocked(enp); } __checkReturn efx_rc_t efx_intr_trigger( __in efx_nic_t *enp, __in unsigned int level) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop = eip->ei_eiop; + const efx_intr_ops_t *eiop = eip->ei_eiop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); return (eiop->eio_trigger(enp, level)); } void efx_intr_status_line( __in efx_nic_t *enp, __out boolean_t *fatalp, __out uint32_t *qmaskp) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop = eip->ei_eiop; + const efx_intr_ops_t *eiop = eip->ei_eiop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); eiop->eio_status_line(enp, fatalp, qmaskp); } void efx_intr_status_message( __in efx_nic_t *enp, __in unsigned int message, __out boolean_t *fatalp) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop = eip->ei_eiop; + const efx_intr_ops_t *eiop = eip->ei_eiop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); eiop->eio_status_message(enp, message, fatalp); } void efx_intr_fatal( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); - efx_intr_ops_t *eiop = eip->ei_eiop; + const efx_intr_ops_t *eiop = eip->ei_eiop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); eiop->eio_fatal(enp); } /* ************************************************************************* */ /* ************************************************************************* */ /* ************************************************************************* */ #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_intr_init( __in efx_nic_t *enp, __in efx_intr_type_t type, __in efsys_mem_t *esmp) { efx_intr_t *eip = &(enp->en_intr); efx_oword_t oword; /* * bug17213 workaround. * * Under legacy interrupts, don't share a level between fatal * interrupts and event queue interrupts. Under MSI-X, they * must share, or we won't get an interrupt. */ if (enp->en_family == EFX_FAMILY_SIENA && eip->ei_type == EFX_INTR_LINE) eip->ei_level = 0x1f; else eip->ei_level = 0; /* Enable all the genuinely fatal interrupts */ EFX_SET_OWORD(oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0); if (enp->en_family >= EFX_FAMILY_SIENA) EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0); EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword); /* Set up the interrupt address register */ EFX_POPULATE_OWORD_3(oword, FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0, FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff, FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32); EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword); return (0); } static void falconsiena_intr_enable( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); efx_oword_t oword; EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level); EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1); EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); } static void falconsiena_intr_disable( __in efx_nic_t *enp) { efx_oword_t oword; EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0); EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); EFSYS_SPIN(10); } static void falconsiena_intr_disable_unlocked( __in efx_nic_t *enp) { efx_oword_t oword; EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST, &oword, B_FALSE); EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0); EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST, &oword, B_FALSE); } static __checkReturn efx_rc_t falconsiena_intr_trigger( __in efx_nic_t *enp, __in unsigned int level) { efx_intr_t *eip = &(enp->en_intr); efx_oword_t oword; unsigned int count; uint32_t sel; efx_rc_t rc; /* bug16757: No event queues can be initialized */ EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); if (level >= EFX_NINTR_SIENA) { rc = EINVAL; goto fail1; } if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL)) return (ENOTSUP); /* avoid EFSYS_PROBE() */ sel = level; /* Trigger a test interrupt */ EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel); EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1); EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); /* * Wait up to 100ms for the interrupt to be raised before restoring * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL */ count = 0; do { EFSYS_SPIN(100); /* 100us */ EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); } while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000); EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level); EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn boolean_t falconsiena_intr_check_fatal( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); efsys_mem_t *esmp = eip->ei_esmp; efx_oword_t oword; /* Read the syndrome */ EFSYS_MEM_READO(esmp, 0, &oword); if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) { EFSYS_PROBE(fatal); /* Clear the fatal interrupt condition */ EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0); EFSYS_MEM_WRITEO(esmp, 0, &oword); return (B_TRUE); } return (B_FALSE); } static void falconsiena_intr_status_line( __in efx_nic_t *enp, __out boolean_t *fatalp, __out uint32_t *qmaskp) { efx_intr_t *eip = &(enp->en_intr); efx_dword_t dword; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); /* * Read the queue mask and implicitly acknowledge the * interrupt. */ EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE); *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0); EFSYS_PROBE1(qmask, uint32_t, *qmaskp); if (*qmaskp & (1U << eip->ei_level)) *fatalp = falconsiena_intr_check_fatal(enp); else *fatalp = B_FALSE; } static void falconsiena_intr_status_message( __in efx_nic_t *enp, __in unsigned int message, __out boolean_t *fatalp) { efx_intr_t *eip = &(enp->en_intr); EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); if (message == eip->ei_level) *fatalp = falconsiena_intr_check_fatal(enp); else *fatalp = B_FALSE; } static void falconsiena_intr_fatal( __in efx_nic_t *enp) { #if EFSYS_OPT_DECODE_INTR_FATAL efx_oword_t fatal; efx_oword_t mem_per; EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal); EFX_ZERO_OWORD(mem_per); if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 || EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0) EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per); if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR, EFX_OWORD_FIELD(mem_per, EFX_DWORD_0), EFX_OWORD_FIELD(mem_per, EFX_DWORD_1)); if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0); if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0) EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR, EFX_OWORD_FIELD(mem_per, EFX_DWORD_0), EFX_OWORD_FIELD(mem_per, EFX_DWORD_1)); #else EFSYS_ASSERT(0); #endif } static void falconsiena_intr_fini( __in efx_nic_t *enp) { efx_oword_t oword; /* Clear the interrupt address register */ EFX_ZERO_OWORD(oword); EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword); } #endif /* EFSYS_OPT_SIENA */ Index: head/sys/dev/sfxge/common/efx_lic.c =================================================================== --- head/sys/dev/sfxge/common/efx_lic.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_lic.c (revision 299517) @@ -1,792 +1,792 @@ /*- * Copyright (c) 2009-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_LICENSING #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t efx_mcdi_fc_license_update_license( __in efx_nic_t *enp); static __checkReturn efx_rc_t efx_mcdi_fc_license_get_key_stats( __in efx_nic_t *enp, __out efx_key_stats_t *eksp); -static efx_lic_ops_t __efx_lic_v1_ops = { +static const efx_lic_ops_t __efx_lic_v1_ops = { efx_mcdi_fc_license_update_license, /* elo_update_licenses */ efx_mcdi_fc_license_get_key_stats, /* elo_get_key_stats */ NULL, /* elo_app_state */ NULL, /* elo_get_id */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON static __checkReturn efx_rc_t efx_mcdi_licensing_update_licenses( __in efx_nic_t *enp); static __checkReturn efx_rc_t efx_mcdi_licensing_get_key_stats( __in efx_nic_t *enp, __out efx_key_stats_t *eksp); static __checkReturn efx_rc_t efx_mcdi_licensed_app_state( __in efx_nic_t *enp, __in uint64_t app_id, __out boolean_t *licensedp); -static efx_lic_ops_t __efx_lic_v2_ops = { +static const efx_lic_ops_t __efx_lic_v2_ops = { efx_mcdi_licensing_update_licenses, /* elo_update_licenses */ efx_mcdi_licensing_get_key_stats, /* elo_get_key_stats */ efx_mcdi_licensed_app_state, /* elo_app_state */ NULL, /* elo_get_id */ }; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD static __checkReturn efx_rc_t efx_mcdi_licensing_v3_update_licenses( __in efx_nic_t *enp); static __checkReturn efx_rc_t efx_mcdi_licensing_v3_report_license( __in efx_nic_t *enp, __out efx_key_stats_t *eksp); static __checkReturn efx_rc_t efx_mcdi_licensing_v3_app_state( __in efx_nic_t *enp, __in uint64_t app_id, __out boolean_t *licensedp); static __checkReturn efx_rc_t efx_mcdi_licensing_v3_get_id( __in efx_nic_t *enp, __in size_t buffer_size, __out uint32_t *typep, __out size_t *lengthp, __out_bcount_part_opt(buffer_size, *lengthp) uint8_t *bufferp); -static efx_lic_ops_t __efx_lic_v3_ops = { +static const efx_lic_ops_t __efx_lic_v3_ops = { efx_mcdi_licensing_v3_update_licenses, /* elo_update_licenses */ efx_mcdi_licensing_v3_report_license, /* elo_get_key_stats */ efx_mcdi_licensing_v3_app_state, /* elo_app_state */ efx_mcdi_licensing_v3_get_id, /* elo_get_id */ }; #endif /* EFSYS_OPT_MEDFORD */ /* V1 Licensing - used in Siena Modena only */ #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t efx_mcdi_fc_license_update_license( __in efx_nic_t *enp) { efx_mcdi_req_t req; uint8_t payload[MC_CMD_FC_IN_LICENSE_LEN]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_FC_OP_LICENSE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_FC_IN_LICENSE_LEN; req.emr_out_buf = payload; req.emr_out_length = 0; MCDI_IN_SET_DWORD(req, FC_IN_LICENSE_OP, MC_CMD_FC_IN_LICENSE_UPDATE_LICENSE); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used != 0) { rc = EIO; goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_fc_license_get_key_stats( __in efx_nic_t *enp, __out efx_key_stats_t *eksp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_FC_IN_LICENSE_LEN, MC_CMD_FC_OUT_LICENSE_LEN)]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_FC_OP_LICENSE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_FC_IN_LICENSE_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_FC_OUT_LICENSE_LEN; MCDI_IN_SET_DWORD(req, FC_IN_LICENSE_OP, MC_CMD_FC_IN_LICENSE_GET_KEY_STATS); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_FC_OUT_LICENSE_LEN) { rc = EMSGSIZE; goto fail2; } eksp->eks_valid = MCDI_OUT_DWORD(req, FC_OUT_LICENSE_VALID_KEYS); eksp->eks_invalid = MCDI_OUT_DWORD(req, FC_OUT_LICENSE_INVALID_KEYS); eksp->eks_blacklisted = MCDI_OUT_DWORD(req, FC_OUT_LICENSE_BLACKLISTED_KEYS); eksp->eks_unverifiable = 0; eksp->eks_wrong_node = 0; eksp->eks_licensed_apps_lo = 0; eksp->eks_licensed_apps_hi = 0; eksp->eks_licensed_features_lo = 0; eksp->eks_licensed_features_hi = 0; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_SIENA */ /* V2 Licensing - used by Huntington family only. See SF-113611-TC */ #if EFSYS_OPT_HUNTINGTON static __checkReturn efx_rc_t efx_mcdi_licensed_app_state( __in efx_nic_t *enp, __in uint64_t app_id, __out boolean_t *licensedp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_LICENSED_APP_STATE_IN_LEN, MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN)]; uint32_t app_state; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); /* V2 licensing supports 32bit app id only */ if ((app_id >> 32) != 0) { rc = EINVAL; goto fail1; } (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_LICENSED_APP_STATE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_LICENSED_APP_STATE_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN; MCDI_IN_SET_DWORD(req, GET_LICENSED_APP_STATE_IN_APP_ID, app_id & 0xffffffff); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail2; } if (req.emr_out_length_used < MC_CMD_GET_LICENSED_APP_STATE_OUT_LEN) { rc = EMSGSIZE; goto fail3; } app_state = (MCDI_OUT_DWORD(req, GET_LICENSED_APP_STATE_OUT_STATE)); if (app_state != MC_CMD_GET_LICENSED_APP_STATE_OUT_NOT_LICENSED) { *licensedp = B_TRUE; } else { *licensedp = B_FALSE; } return (0); 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_licensing_update_licenses( __in efx_nic_t *enp) { efx_mcdi_req_t req; uint8_t payload[MC_CMD_LICENSING_IN_LEN]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_LICENSING; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_LICENSING_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = 0; MCDI_IN_SET_DWORD(req, LICENSING_IN_OP, MC_CMD_LICENSING_IN_OP_UPDATE_LICENSE); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used != 0) { rc = EIO; goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_licensing_get_key_stats( __in efx_nic_t *enp, __out efx_key_stats_t *eksp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_LICENSING_IN_LEN, MC_CMD_LICENSING_OUT_LEN)]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_LICENSING; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_LICENSING_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_LICENSING_OUT_LEN; MCDI_IN_SET_DWORD(req, LICENSING_IN_OP, MC_CMD_LICENSING_IN_OP_GET_KEY_STATS); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_LICENSING_OUT_LEN) { rc = EMSGSIZE; goto fail2; } eksp->eks_valid = MCDI_OUT_DWORD(req, LICENSING_OUT_VALID_APP_KEYS); eksp->eks_invalid = MCDI_OUT_DWORD(req, LICENSING_OUT_INVALID_APP_KEYS); eksp->eks_blacklisted = MCDI_OUT_DWORD(req, LICENSING_OUT_BLACKLISTED_APP_KEYS); eksp->eks_unverifiable = MCDI_OUT_DWORD(req, LICENSING_OUT_UNVERIFIABLE_APP_KEYS); eksp->eks_wrong_node = MCDI_OUT_DWORD(req, LICENSING_OUT_WRONG_NODE_APP_KEYS); eksp->eks_licensed_apps_lo = 0; eksp->eks_licensed_apps_hi = 0; eksp->eks_licensed_features_lo = 0; eksp->eks_licensed_features_hi = 0; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_HUNTINGTON */ /* V3 Licensing - used starting from Medford family. See SF-114884-SW */ #if EFSYS_OPT_MEDFORD static __checkReturn efx_rc_t efx_mcdi_licensing_v3_update_licenses( __in efx_nic_t *enp) { efx_mcdi_req_t req; uint8_t payload[MC_CMD_LICENSING_V3_IN_LEN]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_LICENSING_V3; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_LICENSING_V3_IN_LEN; req.emr_out_buf = NULL; req.emr_out_length = 0; MCDI_IN_SET_DWORD(req, LICENSING_V3_IN_OP, MC_CMD_LICENSING_V3_IN_OP_UPDATE_LICENSE); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_licensing_v3_report_license( __in efx_nic_t *enp, __out efx_key_stats_t *eksp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_LICENSING_V3_IN_LEN, MC_CMD_LICENSING_V3_OUT_LEN)]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_LICENSING_V3; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_LICENSING_V3_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_LICENSING_V3_OUT_LEN; MCDI_IN_SET_DWORD(req, LICENSING_V3_IN_OP, MC_CMD_LICENSING_V3_IN_OP_REPORT_LICENSE); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_LICENSING_V3_OUT_LEN) { rc = EMSGSIZE; goto fail2; } eksp->eks_valid = MCDI_OUT_DWORD(req, LICENSING_V3_OUT_VALID_KEYS); eksp->eks_invalid = MCDI_OUT_DWORD(req, LICENSING_V3_OUT_INVALID_KEYS); eksp->eks_blacklisted = 0; eksp->eks_unverifiable = MCDI_OUT_DWORD(req, LICENSING_V3_OUT_UNVERIFIABLE_KEYS); eksp->eks_wrong_node = MCDI_OUT_DWORD(req, LICENSING_V3_OUT_WRONG_NODE_KEYS); eksp->eks_licensed_apps_lo = MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_APPS_LO); eksp->eks_licensed_apps_hi = MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_APPS_HI); eksp->eks_licensed_features_lo = MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_FEATURES_LO); eksp->eks_licensed_features_hi = MCDI_OUT_DWORD(req, LICENSING_V3_OUT_LICENSED_FEATURES_HI); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_licensing_v3_app_state( __in efx_nic_t *enp, __in uint64_t app_id, __out boolean_t *licensedp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_LICENSED_V3_APP_STATE_IN_LEN, MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN)]; uint32_t app_state; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_MEDFORD); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_LICENSED_V3_APP_STATE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_LICENSED_V3_APP_STATE_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN; MCDI_IN_SET_DWORD(req, GET_LICENSED_V3_APP_STATE_IN_APP_ID_LO, app_id & 0xffffffff); MCDI_IN_SET_DWORD(req, GET_LICENSED_V3_APP_STATE_IN_APP_ID_HI, app_id >> 32); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_LEN) { rc = EMSGSIZE; goto fail2; } app_state = (MCDI_OUT_DWORD(req, GET_LICENSED_V3_APP_STATE_OUT_STATE)); if (app_state != MC_CMD_GET_LICENSED_V3_APP_STATE_OUT_NOT_LICENSED) { *licensedp = B_TRUE; } else { *licensedp = B_FALSE; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_licensing_v3_get_id( __in efx_nic_t *enp, __in size_t buffer_size, __out uint32_t *typep, __out size_t *lengthp, __out_bcount_part_opt(buffer_size, *lengthp) uint8_t *bufferp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_LICENSING_GET_ID_V3_IN_LEN, MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN)]; efx_rc_t rc; req.emr_cmd = MC_CMD_LICENSING_GET_ID_V3; if (bufferp == NULL) { /* Request id type and length only */ req.emr_in_buf = bufferp; req.emr_in_length = MC_CMD_LICENSING_GET_ID_V3_IN_LEN; req.emr_out_buf = bufferp; req.emr_out_length = MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN; (void) memset(payload, 0, sizeof (payload)); } else { /* Request full buffer */ req.emr_in_buf = bufferp; req.emr_in_length = MC_CMD_LICENSING_GET_ID_V3_IN_LEN; req.emr_out_buf = bufferp; req.emr_out_length = MIN(buffer_size, MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN); (void) memset(bufferp, 0, req.emr_out_length); } efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN) { rc = EMSGSIZE; goto fail2; } *typep = MCDI_OUT_DWORD(req, LICENSING_GET_ID_V3_OUT_LICENSE_TYPE); *lengthp = MCDI_OUT_DWORD(req, LICENSING_GET_ID_V3_OUT_LICENSE_ID_LENGTH); if (bufferp == NULL) { /* modify length requirements to indicate to caller the extra buffering ** needed to read the complete output. */ *lengthp += MC_CMD_LICENSING_GET_ID_V3_OUT_LENMIN; } else { /* Shift ID down to start of buffer */ memmove(bufferp, bufferp+MC_CMD_LICENSING_GET_ID_V3_OUT_LICENSE_ID_OFST, *lengthp); memset(bufferp+(*lengthp), 0, MC_CMD_LICENSING_GET_ID_V3_OUT_LICENSE_ID_OFST); } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_lic_init( __in efx_nic_t *enp) { - efx_lic_ops_t *elop; + const efx_lic_ops_t *elop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_LIC)); switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - elop = (efx_lic_ops_t *)&__efx_lic_v1_ops; + elop = &__efx_lic_v1_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - elop = (efx_lic_ops_t *)&__efx_lic_v2_ops; + elop = &__efx_lic_v2_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - elop = (efx_lic_ops_t *)&__efx_lic_v3_ops; + elop = &__efx_lic_v3_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail1; } enp->en_elop = elop; enp->en_mod_flags |= EFX_MOD_LIC; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_lic_fini( __in efx_nic_t *enp) { - efx_lic_ops_t *elop = enp->en_elop; + const efx_lic_ops_t *elop = enp->en_elop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC); enp->en_elop = NULL; enp->en_mod_flags &= ~EFX_MOD_LIC; } __checkReturn efx_rc_t efx_lic_update_licenses( __in efx_nic_t *enp) { - efx_lic_ops_t *elop = enp->en_elop; + const efx_lic_ops_t *elop = enp->en_elop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC); if ((rc = elop->elo_update_licenses(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_lic_get_key_stats( __in efx_nic_t *enp, __out efx_key_stats_t *eksp) { - efx_lic_ops_t *elop = enp->en_elop; + const efx_lic_ops_t *elop = enp->en_elop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC); if ((rc = elop->elo_get_key_stats(enp, eksp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_lic_app_state( __in efx_nic_t *enp, __in uint64_t app_id, __out boolean_t *licensedp) { - efx_lic_ops_t *elop = enp->en_elop; + const efx_lic_ops_t *elop = enp->en_elop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC); if (elop->elo_app_state == NULL) { rc = ENOTSUP; goto fail1; } if ((rc = elop->elo_app_state(enp, app_id, licensedp)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_lic_get_id( __in efx_nic_t *enp, __in size_t buffer_size, __out uint32_t *typep, __out size_t *lengthp, __out_opt uint8_t *bufferp ) { - efx_lic_ops_t *elop = enp->en_elop; + const efx_lic_ops_t *elop = enp->en_elop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_LIC); if (elop->elo_get_id == NULL) { rc = ENOTSUP; goto fail1; } if ((rc = elop->elo_get_id(enp, buffer_size, typep, lengthp, bufferp)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_LICENSING */ Index: head/sys/dev/sfxge/common/efx_mac.c =================================================================== --- head/sys/dev/sfxge/common/efx_mac.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_mac.c (revision 299517) @@ -1,828 +1,828 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_mac_multicast_list_set( __in efx_nic_t *enp); #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_SIENA -static efx_mac_ops_t __efx_siena_mac_ops = { +static const efx_mac_ops_t __efx_siena_mac_ops = { NULL, /* emo_reset */ siena_mac_poll, /* emo_poll */ siena_mac_up, /* emo_up */ siena_mac_reconfigure, /* emo_addr_set */ siena_mac_reconfigure, /* emo_pdu_set */ siena_mac_reconfigure, /* emo_reconfigure */ falconsiena_mac_multicast_list_set, /* emo_multicast_list_set */ NULL, /* emo_filter_set_default_rxq */ NULL, /* emo_filter_default_rxq_clear */ #if EFSYS_OPT_LOOPBACK siena_mac_loopback_set, /* emo_loopback_set */ #endif /* EFSYS_OPT_LOOPBACK */ #if EFSYS_OPT_MAC_STATS efx_mcdi_mac_stats_upload, /* emo_stats_upload */ efx_mcdi_mac_stats_periodic, /* emo_stats_periodic */ siena_mac_stats_update /* emo_stats_update */ #endif /* EFSYS_OPT_MAC_STATS */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_mac_ops_t __efx_ef10_mac_ops = { +static const efx_mac_ops_t __efx_ef10_mac_ops = { NULL, /* emo_reset */ ef10_mac_poll, /* emo_poll */ ef10_mac_up, /* emo_up */ ef10_mac_addr_set, /* emo_addr_set */ ef10_mac_pdu_set, /* emo_pdu_set */ ef10_mac_reconfigure, /* emo_reconfigure */ ef10_mac_multicast_list_set, /* emo_multicast_list_set */ ef10_mac_filter_default_rxq_set, /* emo_filter_default_rxq_set */ ef10_mac_filter_default_rxq_clear, /* emo_filter_default_rxq_clear */ #if EFSYS_OPT_LOOPBACK ef10_mac_loopback_set, /* emo_loopback_set */ #endif /* EFSYS_OPT_LOOPBACK */ #if EFSYS_OPT_MAC_STATS efx_mcdi_mac_stats_upload, /* emo_stats_upload */ efx_mcdi_mac_stats_periodic, /* emo_stats_periodic */ ef10_mac_stats_update /* emo_stats_update */ #endif /* EFSYS_OPT_MAC_STATS */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_mac_pdu_set( __in efx_nic_t *enp, __in size_t pdu) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; uint32_t old_pdu; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); EFSYS_ASSERT(emop != NULL); if (pdu < EFX_MAC_PDU_MIN) { rc = EINVAL; goto fail1; } if (pdu > EFX_MAC_PDU_MAX) { rc = EINVAL; goto fail2; } old_pdu = epp->ep_mac_pdu; epp->ep_mac_pdu = (uint32_t)pdu; if ((rc = emop->emo_pdu_set(enp)) != 0) goto fail3; return (0); fail3: EFSYS_PROBE(fail3); epp->ep_mac_pdu = old_pdu; fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mac_addr_set( __in efx_nic_t *enp, __in uint8_t *addr) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; uint8_t old_addr[6]; uint32_t oui; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if (EFX_MAC_ADDR_IS_MULTICAST(addr)) { rc = EINVAL; goto fail1; } oui = addr[0] << 16 | addr[1] << 8 | addr[2]; if (oui == 0x000000) { rc = EINVAL; goto fail2; } EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr); EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr); if ((rc = emop->emo_addr_set(enp)) != 0) goto fail3; return (0); fail3: EFSYS_PROBE(fail3); EFX_MAC_ADDR_COPY(epp->ep_mac_addr, old_addr); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mac_filter_set( __in efx_nic_t *enp, __in boolean_t all_unicst, __in boolean_t mulcst, __in boolean_t all_mulcst, __in boolean_t brdcst) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; boolean_t old_all_unicst; boolean_t old_mulcst; boolean_t old_all_mulcst; boolean_t old_brdcst; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); old_all_unicst = epp->ep_all_unicst; old_mulcst = epp->ep_mulcst; old_all_mulcst = epp->ep_all_mulcst; old_brdcst = epp->ep_brdcst; epp->ep_all_unicst = all_unicst; epp->ep_mulcst = mulcst; epp->ep_all_mulcst = all_mulcst; epp->ep_brdcst = brdcst; if ((rc = emop->emo_reconfigure(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); epp->ep_all_unicst = old_all_unicst; epp->ep_mulcst = old_mulcst; epp->ep_all_mulcst = old_all_mulcst; epp->ep_brdcst = old_brdcst; return (rc); } __checkReturn efx_rc_t efx_mac_drain( __in efx_nic_t *enp, __in boolean_t enabled) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); EFSYS_ASSERT(emop != NULL); if (epp->ep_mac_drain == enabled) return (0); epp->ep_mac_drain = enabled; if (enabled && emop->emo_reset != NULL) { if ((rc = emop->emo_reset(enp)) != 0) goto fail1; EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_MAC); enp->en_reset_flags &= ~EFX_RESET_PHY; } if ((rc = emop->emo_reconfigure(enp)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mac_up( __in efx_nic_t *enp, __out boolean_t *mac_upp) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if ((rc = emop->emo_up(enp, mac_upp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mac_fcntl_set( __in efx_nic_t *enp, __in unsigned int fcntl, __in boolean_t autoneg) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; - efx_phy_ops_t *epop = epp->ep_epop; + const efx_mac_ops_t *emop = epp->ep_emop; + const efx_phy_ops_t *epop = epp->ep_epop; unsigned int old_fcntl; boolean_t old_autoneg; unsigned int old_adv_cap; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) { rc = EINVAL; goto fail1; } /* * Ignore a request to set flow control auto-negotiation * if the PHY doesn't support it. */ if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) autoneg = B_FALSE; old_fcntl = epp->ep_fcntl; old_autoneg = epp->ep_fcntl_autoneg; old_adv_cap = epp->ep_adv_cap_mask; epp->ep_fcntl = fcntl; epp->ep_fcntl_autoneg = autoneg; /* * Always encode the flow control settings in the advertised * capabilities even if we are not trying to auto-negotiate * them and reconfigure both the PHY and the MAC. */ if (fcntl & EFX_FCNTL_RESPOND) epp->ep_adv_cap_mask |= (1 << EFX_PHY_CAP_PAUSE | 1 << EFX_PHY_CAP_ASYM); else epp->ep_adv_cap_mask &= ~(1 << EFX_PHY_CAP_PAUSE | 1 << EFX_PHY_CAP_ASYM); if (fcntl & EFX_FCNTL_GENERATE) epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM); if ((rc = epop->epo_reconfigure(enp)) != 0) goto fail2; if ((rc = emop->emo_reconfigure(enp)) != 0) goto fail3; return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); epp->ep_fcntl = old_fcntl; epp->ep_fcntl_autoneg = old_autoneg; epp->ep_adv_cap_mask = old_adv_cap; fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_mac_fcntl_get( __in efx_nic_t *enp, __out unsigned int *fcntl_wantedp, __out unsigned int *fcntl_linkp) { efx_port_t *epp = &(enp->en_port); unsigned int wanted = 0; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); /* * Decode the requested flow control settings from the PHY * advertised capabilities. */ if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE)) wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM)) wanted ^= EFX_FCNTL_GENERATE; *fcntl_linkp = epp->ep_fcntl; *fcntl_wantedp = wanted; } __checkReturn efx_rc_t efx_mac_multicast_list_set( __in efx_nic_t *enp, __in_ecount(6*count) uint8_t const *addrs, __in int count) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; uint8_t *old_mulcst_addr_list = NULL; uint32_t old_mulcst_addr_count; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if (count > EFX_MAC_MULTICAST_LIST_MAX) { rc = EINVAL; goto fail1; } old_mulcst_addr_count = epp->ep_mulcst_addr_count; if (old_mulcst_addr_count > 0) { /* Allocate memory to store old list (instead of using stack) */ EFSYS_KMEM_ALLOC(enp->en_esip, old_mulcst_addr_count * EFX_MAC_ADDR_LEN, old_mulcst_addr_list); if (old_mulcst_addr_list == NULL) { rc = ENOMEM; goto fail2; } /* Save the old list in case we need to rollback */ memcpy(old_mulcst_addr_list, epp->ep_mulcst_addr_list, old_mulcst_addr_count * EFX_MAC_ADDR_LEN); } /* Store the new list */ memcpy(epp->ep_mulcst_addr_list, addrs, count * EFX_MAC_ADDR_LEN); epp->ep_mulcst_addr_count = count; if ((rc = emop->emo_multicast_list_set(enp)) != 0) goto fail3; if (old_mulcst_addr_count > 0) { EFSYS_KMEM_FREE(enp->en_esip, old_mulcst_addr_count * EFX_MAC_ADDR_LEN, old_mulcst_addr_list); } return (0); fail3: EFSYS_PROBE(fail3); /* Restore original list on failure */ epp->ep_mulcst_addr_count = old_mulcst_addr_count; if (old_mulcst_addr_count > 0) { memcpy(epp->ep_mulcst_addr_list, old_mulcst_addr_list, old_mulcst_addr_count * EFX_MAC_ADDR_LEN); EFSYS_KMEM_FREE(enp->en_esip, old_mulcst_addr_count * EFX_MAC_ADDR_LEN, old_mulcst_addr_list); } fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mac_filter_default_rxq_set( __in efx_nic_t *enp, __in efx_rxq_t *erp, __in boolean_t using_rss) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if (emop->emo_filter_default_rxq_set != NULL) { rc = emop->emo_filter_default_rxq_set(enp, erp, using_rss); if (rc != 0) goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_mac_filter_default_rxq_clear( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if (emop->emo_filter_default_rxq_clear != NULL) emop->emo_filter_default_rxq_clear(enp); } #if EFSYS_OPT_MAC_STATS #if EFSYS_OPT_NAMES /* START MKCONFIG GENERATED EfxMacStatNamesBlock 054d43a31d2d7a45 */ static const char *__efx_mac_stat_name[] = { "rx_octets", "rx_pkts", "rx_unicst_pkts", "rx_multicst_pkts", "rx_brdcst_pkts", "rx_pause_pkts", "rx_le_64_pkts", "rx_65_to_127_pkts", "rx_128_to_255_pkts", "rx_256_to_511_pkts", "rx_512_to_1023_pkts", "rx_1024_to_15xx_pkts", "rx_ge_15xx_pkts", "rx_errors", "rx_fcs_errors", "rx_drop_events", "rx_false_carrier_errors", "rx_symbol_errors", "rx_align_errors", "rx_internal_errors", "rx_jabber_pkts", "rx_lane0_char_err", "rx_lane1_char_err", "rx_lane2_char_err", "rx_lane3_char_err", "rx_lane0_disp_err", "rx_lane1_disp_err", "rx_lane2_disp_err", "rx_lane3_disp_err", "rx_match_fault", "rx_nodesc_drop_cnt", "tx_octets", "tx_pkts", "tx_unicst_pkts", "tx_multicst_pkts", "tx_brdcst_pkts", "tx_pause_pkts", "tx_le_64_pkts", "tx_65_to_127_pkts", "tx_128_to_255_pkts", "tx_256_to_511_pkts", "tx_512_to_1023_pkts", "tx_1024_to_15xx_pkts", "tx_ge_15xx_pkts", "tx_errors", "tx_sgl_col_pkts", "tx_mult_col_pkts", "tx_ex_col_pkts", "tx_late_col_pkts", "tx_def_pkts", "tx_ex_def_pkts", "pm_trunc_bb_overflow", "pm_discard_bb_overflow", "pm_trunc_vfifo_full", "pm_discard_vfifo_full", "pm_trunc_qbb", "pm_discard_qbb", "pm_discard_mapping", "rxdp_q_disabled_pkts", "rxdp_di_dropped_pkts", "rxdp_streaming_pkts", "rxdp_hlb_fetch", "rxdp_hlb_wait", "vadapter_rx_unicast_packets", "vadapter_rx_unicast_bytes", "vadapter_rx_multicast_packets", "vadapter_rx_multicast_bytes", "vadapter_rx_broadcast_packets", "vadapter_rx_broadcast_bytes", "vadapter_rx_bad_packets", "vadapter_rx_bad_bytes", "vadapter_rx_overflow", "vadapter_tx_unicast_packets", "vadapter_tx_unicast_bytes", "vadapter_tx_multicast_packets", "vadapter_tx_multicast_bytes", "vadapter_tx_broadcast_packets", "vadapter_tx_broadcast_bytes", "vadapter_tx_bad_packets", "vadapter_tx_bad_bytes", "vadapter_tx_overflow", }; /* END MKCONFIG GENERATED EfxMacStatNamesBlock */ __checkReturn const char * efx_mac_stat_name( __in efx_nic_t *enp, __in unsigned int id) { _NOTE(ARGUNUSED(enp)) EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(id, <, EFX_MAC_NSTATS); return (__efx_mac_stat_name[id]); } #endif /* EFSYS_OPT_NAMES */ __checkReturn efx_rc_t efx_mac_stats_upload( __in efx_nic_t *enp, __in efsys_mem_t *esmp) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); EFSYS_ASSERT(emop != NULL); /* * Don't assert !ep_mac_stats_pending, because the client might * have failed to finalise statistics when previously stopping * the port. */ if ((rc = emop->emo_stats_upload(enp, esmp)) != 0) goto fail1; epp->ep_mac_stats_pending = B_TRUE; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mac_stats_periodic( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __in uint16_t period_ms, __in boolean_t events) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); EFSYS_ASSERT(emop != NULL); if (emop->emo_stats_periodic == NULL) { rc = EINVAL; goto fail1; } if ((rc = emop->emo_stats_periodic(enp, esmp, period_ms, events)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mac_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_MAC_NSTATS) efsys_stat_t *essp, __inout_opt uint32_t *generationp) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); EFSYS_ASSERT(emop != NULL); rc = emop->emo_stats_update(enp, esmp, essp, generationp); if (rc == 0) epp->ep_mac_stats_pending = B_FALSE; return (rc); } #endif /* EFSYS_OPT_MAC_STATS */ __checkReturn efx_rc_t efx_mac_select( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_mac_type_t type = EFX_MAC_INVALID; - efx_mac_ops_t *emop; + const efx_mac_ops_t *emop; int rc = EINVAL; switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: emop = &__efx_siena_mac_ops; type = EFX_MAC_SIENA; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: emop = &__efx_ef10_mac_ops; type = EFX_MAC_HUNTINGTON; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: emop = &__efx_ef10_mac_ops; type = EFX_MAC_MEDFORD; break; #endif /* EFSYS_OPT_MEDFORD */ default: rc = EINVAL; goto fail1; } EFSYS_ASSERT(type != EFX_MAC_INVALID); EFSYS_ASSERT3U(type, <, EFX_MAC_NTYPES); EFSYS_ASSERT(emop != NULL); epp->ep_emop = emop; epp->ep_mac_type = type; if (emop->emo_reset != NULL) { if ((rc = emop->emo_reset(enp)) != 0) goto fail2; EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_MAC); enp->en_reset_flags &= ~EFX_RESET_MAC; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_SIENA #define EFX_MAC_HASH_BITS (1 << 8) /* Compute the multicast hash as used on Falcon and Siena. */ static void falconsiena_mac_multicast_hash_compute( __in_ecount(6*count) uint8_t const *addrs, __in int count, __out efx_oword_t *hash_low, __out efx_oword_t *hash_high) { uint32_t crc, index; int i; EFSYS_ASSERT(hash_low != NULL); EFSYS_ASSERT(hash_high != NULL); EFX_ZERO_OWORD(*hash_low); EFX_ZERO_OWORD(*hash_high); for (i = 0; i < count; i++) { /* Calculate hash bucket (IEEE 802.3 CRC32 of the MAC addr) */ crc = efx_crc32_calculate(0xffffffff, addrs, EFX_MAC_ADDR_LEN); index = crc % EFX_MAC_HASH_BITS; if (index < 128) { EFX_SET_OWORD_BIT(*hash_low, index); } else { EFX_SET_OWORD_BIT(*hash_high, index - 128); } addrs += EFX_MAC_ADDR_LEN; } } static __checkReturn efx_rc_t falconsiena_mac_multicast_list_set( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_oword_t old_hash[2]; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash)); falconsiena_mac_multicast_hash_compute(epp->ep_mulcst_addr_list, epp->ep_mulcst_addr_count, &epp->ep_multicst_hash[0], &epp->ep_multicst_hash[1]); if ((rc = emop->emo_reconfigure(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash)); return (rc); } #endif /* EFSYS_OPT_SIENA */ Index: head/sys/dev/sfxge/common/efx_mcdi.c =================================================================== --- head/sys/dev/sfxge/common/efx_mcdi.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_mcdi.c (revision 299517) @@ -1,2287 +1,2287 @@ /*- * Copyright (c) 2008-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_MCDI /* * There are three versions of the MCDI interface: * - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers. * - MCDIv1: Siena firmware and Huntington BootROM. * - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM. * Transport uses MCDIv2 headers. * * MCDIv2 Header NOT_EPOCH flag * ---------------------------- * A new epoch begins at initial startup or after an MC reboot, and defines when * the MC should reject stale MCDI requests. * * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1. * * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0. */ #if EFSYS_OPT_SIENA -static efx_mcdi_ops_t __efx_mcdi_siena_ops = { +static const efx_mcdi_ops_t __efx_mcdi_siena_ops = { siena_mcdi_init, /* emco_init */ siena_mcdi_send_request, /* emco_send_request */ siena_mcdi_poll_reboot, /* emco_poll_reboot */ siena_mcdi_poll_response, /* emco_poll_response */ siena_mcdi_read_response, /* emco_read_response */ siena_mcdi_fini, /* emco_fini */ siena_mcdi_feature_supported, /* emco_feature_supported */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_mcdi_ops_t __efx_mcdi_ef10_ops = { +static const efx_mcdi_ops_t __efx_mcdi_ef10_ops = { ef10_mcdi_init, /* emco_init */ ef10_mcdi_send_request, /* emco_send_request */ ef10_mcdi_poll_reboot, /* emco_poll_reboot */ ef10_mcdi_poll_response, /* emco_poll_response */ ef10_mcdi_read_response, /* emco_read_response */ ef10_mcdi_fini, /* emco_fini */ ef10_mcdi_feature_supported, /* emco_feature_supported */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_mcdi_init( __in efx_nic_t *enp, __in const efx_mcdi_transport_t *emtp) { - efx_mcdi_ops_t *emcop; + const efx_mcdi_ops_t *emcop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - emcop = (efx_mcdi_ops_t *)&__efx_mcdi_siena_ops; + emcop = &__efx_mcdi_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - emcop = (efx_mcdi_ops_t *)&__efx_mcdi_ef10_ops; + emcop = &__efx_mcdi_ef10_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - emcop = (efx_mcdi_ops_t *)&__efx_mcdi_ef10_ops; + emcop = &__efx_mcdi_ef10_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail1; } if (enp->en_features & EFX_FEATURE_MCDI_DMA) { /* MCDI requires a DMA buffer in host memory */ if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) { rc = EINVAL; goto fail2; } } enp->en_mcdi.em_emtp = emtp; if (emcop != NULL && emcop->emco_init != NULL) { if ((rc = emcop->emco_init(enp, emtp)) != 0) goto fail3; } enp->en_mcdi.em_emcop = emcop; enp->en_mod_flags |= EFX_MOD_MCDI; return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); enp->en_mcdi.em_emcop = NULL; enp->en_mcdi.em_emtp = NULL; enp->en_mod_flags &= ~EFX_MOD_MCDI; return (rc); } void efx_mcdi_fini( __in efx_nic_t *enp) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI); if (emcop != NULL && emcop->emco_fini != NULL) emcop->emco_fini(enp); emip->emi_port = 0; emip->emi_aborted = 0; enp->en_mcdi.em_emcop = NULL; enp->en_mod_flags &= ~EFX_MOD_MCDI; } void efx_mcdi_new_epoch( __in efx_nic_t *enp) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); int state; /* Start a new epoch (allow fresh MCDI requests to succeed) */ EFSYS_LOCK(enp->en_eslp, state); emip->emi_new_epoch = B_TRUE; EFSYS_UNLOCK(enp->en_eslp, state); } static void efx_mcdi_send_request( __in efx_nic_t *enp, __in void *hdrp, __in size_t hdr_len, __in void *sdup, __in size_t sdu_len) { - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len); } static efx_rc_t efx_mcdi_poll_reboot( __in efx_nic_t *enp) { - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; efx_rc_t rc; rc = emcop->emco_poll_reboot(enp); return (rc); } static boolean_t efx_mcdi_poll_response( __in efx_nic_t *enp) { - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; boolean_t available; available = emcop->emco_poll_response(enp); return (available); } static void efx_mcdi_read_response( __in efx_nic_t *enp, __out void *bufferp, __in size_t offset, __in size_t length) { - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; emcop->emco_read_response(enp, bufferp, offset, length); } void efx_mcdi_request_start( __in efx_nic_t *enp, __in efx_mcdi_req_t *emrp, __in boolean_t ev_cpl) { #if EFSYS_OPT_MCDI_LOGGING const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; #endif efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efx_dword_t hdr[2]; size_t hdr_len; unsigned int max_version; unsigned int seq; unsigned int xflags; boolean_t new_epoch; int state; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); /* * efx_mcdi_request_start() is naturally serialised against both * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(), * by virtue of there only being one outstanding MCDI request. * Unfortunately, upper layers may also call efx_mcdi_request_abort() * at any time, to timeout a pending mcdi request, That request may * then subsequently complete, meaning efx_mcdi_ev_cpl() or * efx_mcdi_ev_death() may end up running in parallel with * efx_mcdi_request_start(). This race is handled by ensuring that * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the * en_eslp lock. */ EFSYS_LOCK(enp->en_eslp, state); EFSYS_ASSERT(emip->emi_pending_req == NULL); emip->emi_pending_req = emrp; emip->emi_ev_cpl = ev_cpl; emip->emi_poll_cnt = 0; seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ); new_epoch = emip->emi_new_epoch; max_version = emip->emi_max_version; EFSYS_UNLOCK(enp->en_eslp, state); xflags = 0; if (ev_cpl) xflags |= MCDI_HEADER_XFLAGS_EVREQ; /* * Huntington firmware supports MCDIv2, but the Huntington BootROM only * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where * possible to support this. */ if ((max_version >= 2) && ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) || (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1))) { /* Construct MCDI v2 header */ hdr_len = sizeof (hdr); EFX_POPULATE_DWORD_8(hdr[0], MCDI_HEADER_CODE, MC_CMD_V2_EXTN, MCDI_HEADER_RESYNC, 1, MCDI_HEADER_DATALEN, 0, MCDI_HEADER_SEQ, seq, MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, MCDI_HEADER_ERROR, 0, MCDI_HEADER_RESPONSE, 0, MCDI_HEADER_XFLAGS, xflags); EFX_POPULATE_DWORD_2(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd, MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length); } else { /* Construct MCDI v1 header */ hdr_len = sizeof (hdr[0]); EFX_POPULATE_DWORD_8(hdr[0], MCDI_HEADER_CODE, emrp->emr_cmd, MCDI_HEADER_RESYNC, 1, MCDI_HEADER_DATALEN, emrp->emr_in_length, MCDI_HEADER_SEQ, seq, MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, MCDI_HEADER_ERROR, 0, MCDI_HEADER_RESPONSE, 0, MCDI_HEADER_XFLAGS, xflags); } #if EFSYS_OPT_MCDI_LOGGING if (emtp->emt_logger != NULL) { emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST, &hdr, hdr_len, emrp->emr_in_buf, emrp->emr_in_length); } #endif /* EFSYS_OPT_MCDI_LOGGING */ efx_mcdi_send_request(enp, &hdr[0], hdr_len, emrp->emr_in_buf, emrp->emr_in_length); } static void efx_mcdi_read_response_header( __in efx_nic_t *enp, __inout efx_mcdi_req_t *emrp) { #if EFSYS_OPT_MCDI_LOGGING const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; #endif /* EFSYS_OPT_MCDI_LOGGING */ efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efx_dword_t hdr[2]; unsigned int hdr_len; unsigned int data_len; unsigned int seq; unsigned int cmd; unsigned int error; efx_rc_t rc; EFSYS_ASSERT(emrp != NULL); efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0])); hdr_len = sizeof (hdr[0]); cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE); seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ); error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR); if (cmd != MC_CMD_V2_EXTN) { data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN); } else { efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); hdr_len += sizeof (hdr[1]); cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD); data_len = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN); } if (error && (data_len == 0)) { /* The MC has rebooted since the request was sent. */ EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); efx_mcdi_poll_reboot(enp); rc = EIO; goto fail1; } if ((cmd != emrp->emr_cmd) || (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { /* Response is for a different request */ rc = EIO; goto fail2; } if (error) { efx_dword_t err[2]; unsigned int err_len = MIN(data_len, sizeof (err)); int err_code = MC_CMD_ERR_EPROTO; int err_arg = 0; /* Read error code (and arg num for MCDI v2 commands) */ efx_mcdi_read_response(enp, &err, hdr_len, err_len); if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t))) err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0); #ifdef WITH_MCDI_V2 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t))) err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0); #endif emrp->emr_err_code = err_code; emrp->emr_err_arg = err_arg; #if EFSYS_OPT_MCDI_PROXY_AUTH if ((err_code == MC_CMD_ERR_PROXY_PENDING) && (err_len == sizeof (err))) { /* * The MCDI request would normally fail with EPERM, but * firmware has forwarded it to an authorization agent * attached to a privileged PF. * * Save the authorization request handle. The client * must wait for a PROXY_RESPONSE event, or timeout. */ emrp->emr_proxy_handle = err_arg; } #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ #if EFSYS_OPT_MCDI_LOGGING if (emtp->emt_logger != NULL) { emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_RESPONSE, &hdr, hdr_len, &err, err_len); } #endif /* EFSYS_OPT_MCDI_LOGGING */ if (!emrp->emr_quiet) { EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd, int, err_code, int, err_arg); } rc = efx_mcdi_request_errcode(err_code); goto fail3; } emrp->emr_rc = 0; emrp->emr_out_length_used = data_len; #if EFSYS_OPT_MCDI_PROXY_AUTH emrp->emr_proxy_handle = 0; #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ return; fail3: fail2: fail1: emrp->emr_rc = rc; emrp->emr_out_length_used = 0; } static void efx_mcdi_finish_response( __in efx_nic_t *enp, __in efx_mcdi_req_t *emrp) { #if EFSYS_OPT_MCDI_LOGGING const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; #endif /* EFSYS_OPT_MCDI_LOGGING */ efx_dword_t hdr[2]; unsigned int hdr_len; size_t bytes; if (emrp->emr_out_buf == NULL) return; /* Read the command header to detect MCDI response format */ hdr_len = sizeof (hdr[0]); efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len); if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) { /* * Read the actual payload length. The length given in the event * is only correct for responses with the V1 format. */ efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); hdr_len += sizeof (hdr[1]); emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN); } /* Copy payload out into caller supplied buffer */ bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length); efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes); #if EFSYS_OPT_MCDI_LOGGING if (emtp->emt_logger != NULL) { emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_RESPONSE, &hdr, hdr_len, emrp->emr_out_buf, bytes); } #endif /* EFSYS_OPT_MCDI_LOGGING */ } __checkReturn boolean_t efx_mcdi_request_poll( __in efx_nic_t *enp) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efx_mcdi_req_t *emrp; int state; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); /* Serialise against post-watchdog efx_mcdi_ev* */ EFSYS_LOCK(enp->en_eslp, state); EFSYS_ASSERT(emip->emi_pending_req != NULL); EFSYS_ASSERT(!emip->emi_ev_cpl); emrp = emip->emi_pending_req; /* Check for reboot atomically w.r.t efx_mcdi_request_start */ if (emip->emi_poll_cnt++ == 0) { if ((rc = efx_mcdi_poll_reboot(enp)) != 0) { emip->emi_pending_req = NULL; EFSYS_UNLOCK(enp->en_eslp, state); goto fail1; } } /* Check if a response is available */ if (efx_mcdi_poll_response(enp) == B_FALSE) { EFSYS_UNLOCK(enp->en_eslp, state); return (B_FALSE); } /* Read the response header */ efx_mcdi_read_response_header(enp, emrp); /* Request complete */ emip->emi_pending_req = NULL; EFSYS_UNLOCK(enp->en_eslp, state); if ((rc = emrp->emr_rc) != 0) goto fail2; efx_mcdi_finish_response(enp, emrp); return (B_TRUE); fail2: if (!emrp->emr_quiet) EFSYS_PROBE(fail2); fail1: if (!emrp->emr_quiet) EFSYS_PROBE1(fail1, efx_rc_t, rc); /* Reboot/Assertion */ if (rc == EIO || rc == EINTR) efx_mcdi_raise_exception(enp, emrp, rc); return (B_TRUE); } __checkReturn boolean_t efx_mcdi_request_abort( __in efx_nic_t *enp) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efx_mcdi_req_t *emrp; boolean_t aborted; int state; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); /* * efx_mcdi_ev_* may have already completed this event, and be * spinning/blocked on the upper layer lock. So it *is* legitimate * to for emi_pending_req to be NULL. If there is a pending event * completed request, then provide a "credit" to allow * efx_mcdi_ev_cpl() to accept a single spurious completion. */ EFSYS_LOCK(enp->en_eslp, state); emrp = emip->emi_pending_req; aborted = (emrp != NULL); if (aborted) { emip->emi_pending_req = NULL; /* Error the request */ emrp->emr_out_length_used = 0; emrp->emr_rc = ETIMEDOUT; /* Provide a credit for seqno/emr_pending_req mismatches */ if (emip->emi_ev_cpl) ++emip->emi_aborted; /* * The upper layer has called us, so we don't * need to complete the request. */ } EFSYS_UNLOCK(enp->en_eslp, state); return (aborted); } __checkReturn efx_rc_t efx_mcdi_request_errcode( __in unsigned int err) { switch (err) { /* MCDI v1 */ case MC_CMD_ERR_EPERM: return (EACCES); case MC_CMD_ERR_ENOENT: return (ENOENT); case MC_CMD_ERR_EINTR: return (EINTR); case MC_CMD_ERR_EACCES: return (EACCES); case MC_CMD_ERR_EBUSY: return (EBUSY); case MC_CMD_ERR_EINVAL: return (EINVAL); case MC_CMD_ERR_EDEADLK: return (EDEADLK); case MC_CMD_ERR_ENOSYS: return (ENOTSUP); case MC_CMD_ERR_ETIME: return (ETIMEDOUT); case MC_CMD_ERR_ENOTSUP: return (ENOTSUP); case MC_CMD_ERR_EALREADY: return (EALREADY); /* MCDI v2 */ #ifdef MC_CMD_ERR_EAGAIN case MC_CMD_ERR_EAGAIN: return (EAGAIN); #endif #ifdef MC_CMD_ERR_ENOSPC case MC_CMD_ERR_ENOSPC: return (ENOSPC); #endif case MC_CMD_ERR_ALLOC_FAIL: return (ENOMEM); case MC_CMD_ERR_NO_VADAPTOR: return (ENOENT); case MC_CMD_ERR_NO_EVB_PORT: return (ENOENT); case MC_CMD_ERR_NO_VSWITCH: return (ENODEV); case MC_CMD_ERR_VLAN_LIMIT: return (EINVAL); case MC_CMD_ERR_BAD_PCI_FUNC: return (ENODEV); case MC_CMD_ERR_BAD_VLAN_MODE: return (EINVAL); case MC_CMD_ERR_BAD_VSWITCH_TYPE: return (EINVAL); case MC_CMD_ERR_BAD_VPORT_TYPE: return (EINVAL); case MC_CMD_ERR_MAC_EXIST: return (EEXIST); case MC_CMD_ERR_PROXY_PENDING: return (EAGAIN); default: EFSYS_PROBE1(mc_pcol_error, int, err); return (EIO); } } void efx_mcdi_raise_exception( __in efx_nic_t *enp, __in_opt efx_mcdi_req_t *emrp, __in int rc) { const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; efx_mcdi_exception_t exception; /* Reboot or Assertion failure only */ EFSYS_ASSERT(rc == EIO || rc == EINTR); /* * If MC_CMD_REBOOT causes a reboot (dependent on parameters), * then the EIO is not worthy of an exception. */ if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO) return; exception = (rc == EIO) ? EFX_MCDI_EXCEPTION_MC_REBOOT : EFX_MCDI_EXCEPTION_MC_BADASSERT; emtp->emt_exception(emtp->emt_context, exception); } void efx_mcdi_execute( __in efx_nic_t *enp, __inout efx_mcdi_req_t *emrp) { const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); emrp->emr_quiet = B_FALSE; emtp->emt_execute(emtp->emt_context, emrp); } void efx_mcdi_execute_quiet( __in efx_nic_t *enp, __inout efx_mcdi_req_t *emrp) { const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); emrp->emr_quiet = B_TRUE; emtp->emt_execute(emtp->emt_context, emrp); } void efx_mcdi_ev_cpl( __in efx_nic_t *enp, __in unsigned int seq, __in unsigned int outlen, __in int errcode) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; efx_mcdi_req_t *emrp; int state; EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); /* * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start() * when we're completing an aborted request. */ EFSYS_LOCK(enp->en_eslp, state); if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl || (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { EFSYS_ASSERT(emip->emi_aborted > 0); if (emip->emi_aborted > 0) --emip->emi_aborted; EFSYS_UNLOCK(enp->en_eslp, state); return; } emrp = emip->emi_pending_req; emip->emi_pending_req = NULL; EFSYS_UNLOCK(enp->en_eslp, state); if (emip->emi_max_version >= 2) { /* MCDIv2 response details do not fit into an event. */ efx_mcdi_read_response_header(enp, emrp); } else { if (errcode != 0) { if (!emrp->emr_quiet) { EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, int, errcode); } emrp->emr_out_length_used = 0; emrp->emr_rc = efx_mcdi_request_errcode(errcode); } else { emrp->emr_out_length_used = outlen; emrp->emr_rc = 0; } } if (errcode == 0) { efx_mcdi_finish_response(enp, emrp); } emtp->emt_ev_cpl(emtp->emt_context); } #if EFSYS_OPT_MCDI_PROXY_AUTH __checkReturn efx_rc_t efx_mcdi_get_proxy_handle( __in efx_nic_t *enp, __in efx_mcdi_req_t *emrp, __out uint32_t *handlep) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efx_rc_t rc; /* * Return proxy handle from MCDI request that returned with error * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching * PROXY_RESPONSE event. */ if ((emrp == NULL) || (handlep == NULL)) { rc = EINVAL; goto fail1; } if ((emrp->emr_rc != 0) && (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) { *handlep = emrp->emr_proxy_handle; rc = 0; } else { *handlep = 0; rc = ENOENT; } return (rc); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_mcdi_ev_proxy_response( __in efx_nic_t *enp, __in unsigned int handle, __in unsigned int status) { const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; efx_rc_t rc; /* * Handle results of an authorization request for a privileged MCDI * command. If authorization was granted then we must re-issue the * original MCDI request. If authorization failed or timed out, * then the original MCDI request should be completed with the * result code from this event. */ rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status); emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc); } #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ void efx_mcdi_ev_death( __in efx_nic_t *enp, __in int rc) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; efx_mcdi_req_t *emrp = NULL; boolean_t ev_cpl; int state; /* * The MCDI request (if there is one) has been terminated, either * by a BADASSERT or REBOOT event. * * If there is an outstanding event-completed MCDI operation, then we * will never receive the completion event (because both MCDI * completions and BADASSERT events are sent to the same evq). So * complete this MCDI op. * * This function might run in parallel with efx_mcdi_request_poll() * for poll completed mcdi requests, and also with * efx_mcdi_request_start() for post-watchdog completions. */ EFSYS_LOCK(enp->en_eslp, state); emrp = emip->emi_pending_req; ev_cpl = emip->emi_ev_cpl; if (emrp != NULL && emip->emi_ev_cpl) { emip->emi_pending_req = NULL; emrp->emr_out_length_used = 0; emrp->emr_rc = rc; ++emip->emi_aborted; } /* * Since we're running in parallel with a request, consume the * status word before dropping the lock. */ if (rc == EIO || rc == EINTR) { EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); (void) efx_mcdi_poll_reboot(enp); emip->emi_new_epoch = B_TRUE; } EFSYS_UNLOCK(enp->en_eslp, state); efx_mcdi_raise_exception(enp, emrp, rc); if (emrp != NULL && ev_cpl) emtp->emt_ev_cpl(emtp->emt_context); } __checkReturn efx_rc_t efx_mcdi_version( __in efx_nic_t *enp, __out_ecount_opt(4) uint16_t versionp[4], __out_opt uint32_t *buildp, __out_opt efx_mcdi_boot_t *statusp) { efx_mcdi_req_t req; uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN, MC_CMD_GET_VERSION_OUT_LEN), MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN, MC_CMD_GET_BOOT_STATUS_OUT_LEN))]; efx_word_t *ver_words; uint16_t version[4]; uint32_t build; efx_mcdi_boot_t status; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_VERSION; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } /* bootrom support */ if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) { version[0] = version[1] = version[2] = version[3] = 0; build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); goto version; } if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) { rc = EMSGSIZE; goto fail2; } ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION); version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0); version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0); version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0); version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0); build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); version: /* The bootrom doesn't understand BOOT_STATUS */ if (MC_FW_VERSION_IS_BOOTLOADER(build)) { status = EFX_MCDI_BOOT_ROM; goto out; } (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_BOOT_STATUS; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN; efx_mcdi_execute_quiet(enp, &req); if (req.emr_rc == EACCES) { /* Unprivileged functions cannot access BOOT_STATUS */ status = EFX_MCDI_BOOT_PRIMARY; version[0] = version[1] = version[2] = version[3] = 0; build = 0; goto out; } if (req.emr_rc != 0) { rc = req.emr_rc; goto fail3; } if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) { rc = EMSGSIZE; goto fail4; } if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS, GET_BOOT_STATUS_OUT_FLAGS_PRIMARY)) status = EFX_MCDI_BOOT_PRIMARY; else status = EFX_MCDI_BOOT_SECONDARY; out: if (versionp != NULL) memcpy(versionp, version, sizeof (version)); if (buildp != NULL) *buildp = build; if (statusp != NULL) *statusp = status; 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_do_reboot( __in efx_nic_t *enp, __in boolean_t after_assertion) { uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)]; efx_mcdi_req_t req; efx_rc_t rc; /* * We could require the caller to have caused en_mod_flags=0 to * call this function. This doesn't help the other port though, * who's about to get the MC ripped out from underneath them. * Since they have to cope with the subsequent fallout of MCDI * failures, we should as well. */ EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_REBOOT; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_REBOOT_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_REBOOT_OUT_LEN; MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0)); efx_mcdi_execute_quiet(enp, &req); if (req.emr_rc == EACCES) { /* Unprivileged functions cannot reboot the MC. */ goto out; } /* A successful reboot request returns EIO. */ if (req.emr_rc != 0 && req.emr_rc != EIO) { rc = req.emr_rc; goto fail1; } out: return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_reboot( __in efx_nic_t *enp) { return (efx_mcdi_do_reboot(enp, B_FALSE)); } __checkReturn efx_rc_t efx_mcdi_exit_assertion_handler( __in efx_nic_t *enp) { return (efx_mcdi_do_reboot(enp, B_TRUE)); } __checkReturn efx_rc_t efx_mcdi_read_assertion( __in efx_nic_t *enp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN, MC_CMD_GET_ASSERTS_OUT_LEN)]; const char *reason; unsigned int flags; unsigned int index; unsigned int ofst; int retry; efx_rc_t rc; /* * Before we attempt to chat to the MC, we should verify that the MC * isn't in it's assertion handler, either due to a previous reboot, * or because we're reinitializing due to an eec_exception(). * * Use GET_ASSERTS to read any assertion state that may be present. * Retry this command twice. Once because a boot-time assertion failure * might cause the 1st MCDI request to fail. And once again because * we might race with efx_mcdi_exit_assertion_handler() running on * partner port(s) on the same NIC. */ retry = 2; do { (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_ASSERTS; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN; MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1); efx_mcdi_execute_quiet(enp, &req); } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0); if (req.emr_rc != 0) { if (req.emr_rc == EACCES) { /* Unprivileged functions cannot clear assertions. */ goto out; } rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) { rc = EMSGSIZE; goto fail2; } /* Print out any assertion state recorded */ flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS); if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) return (0); reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) ? "system-level assertion" : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) ? "thread-level assertion" : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) ? "watchdog reset" : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP) ? "illegal address trap" : "unknown assertion"; EFSYS_PROBE3(mcpu_assertion, const char *, reason, unsigned int, MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS), unsigned int, MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS)); /* Print out the registers (r1 ... r31) */ ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; for (index = 1; index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM; index++) { EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int, EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst), EFX_DWORD_0)); ofst += sizeof (efx_dword_t); } EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN); out: return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } /* * Internal routines for for specific MCDI requests. */ __checkReturn efx_rc_t efx_mcdi_drv_attach( __in efx_nic_t *enp, __in boolean_t attach) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN, MC_CMD_DRV_ATTACH_EXT_OUT_LEN)]; uint32_t flags; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_DRV_ATTACH; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN; /* * Use DONT_CARE for the datapath firmware type to ensure that the * driver can attach to an unprivileged function. The datapath firmware * type to use is controlled by the 'sfboot' utility. */ MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0); MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1); MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) { rc = EMSGSIZE; goto fail2; } if (attach == B_FALSE) { flags = 0; } else if (enp->en_family == EFX_FAMILY_SIENA) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); /* Create synthetic privileges for Siena functions */ flags = EFX_NIC_FUNC_LINKCTRL | EFX_NIC_FUNC_TRUSTED; if (emip->emi_port == 1) flags |= EFX_NIC_FUNC_PRIMARY; } else { EFX_STATIC_ASSERT(EFX_NIC_FUNC_PRIMARY == (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY)); EFX_STATIC_ASSERT(EFX_NIC_FUNC_LINKCTRL == (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL)); EFX_STATIC_ASSERT(EFX_NIC_FUNC_TRUSTED == (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)); /* Save function privilege flags (EF10 and later) */ if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_EXT_OUT_LEN) { rc = EMSGSIZE; goto fail3; } flags = MCDI_OUT_DWORD(req, DRV_ATTACH_EXT_OUT_FUNC_FLAGS); } encp->enc_func_flags = flags; return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_get_board_cfg( __in efx_nic_t *enp, __out_opt uint32_t *board_typep, __out_opt efx_dword_t *capabilitiesp, __out_ecount_opt(6) uint8_t mac_addrp[6]) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN, MC_CMD_GET_BOARD_CFG_OUT_LENMIN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_BOARD_CFG; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { rc = EMSGSIZE; goto fail2; } if (mac_addrp != NULL) { uint8_t *addrp; if (emip->emi_port == 1) { addrp = MCDI_OUT2(req, uint8_t, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0); } else if (emip->emi_port == 2) { addrp = MCDI_OUT2(req, uint8_t, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1); } else { rc = EINVAL; goto fail3; } EFX_MAC_ADDR_COPY(mac_addrp, addrp); } if (capabilitiesp != NULL) { if (emip->emi_port == 1) { *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, GET_BOARD_CFG_OUT_CAPABILITIES_PORT0); } else if (emip->emi_port == 2) { *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, GET_BOARD_CFG_OUT_CAPABILITIES_PORT1); } else { rc = EINVAL; goto fail4; } } if (board_typep != NULL) { *board_typep = MCDI_OUT_DWORD(req, GET_BOARD_CFG_OUT_BOARD_TYPE); } return (0); 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_get_resource_limits( __in efx_nic_t *enp, __out_opt uint32_t *nevqp, __out_opt uint32_t *nrxqp, __out_opt uint32_t *ntxqp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN, MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) { rc = EMSGSIZE; goto fail2; } if (nevqp != NULL) *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ); if (nrxqp != NULL) *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ); if (ntxqp != NULL) *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_get_phy_cfg( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN, MC_CMD_GET_PHY_CFG_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_PHY_CFG; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) { rc = EMSGSIZE; goto fail2; } encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE); #if EFSYS_OPT_NAMES (void) strncpy(encp->enc_phy_name, MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME), MIN(sizeof (encp->enc_phy_name) - 1, MC_CMD_GET_PHY_CFG_OUT_NAME_LEN)); #endif /* EFSYS_OPT_NAMES */ (void) memset(encp->enc_phy_revision, 0, sizeof (encp->enc_phy_revision)); memcpy(encp->enc_phy_revision, MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION), MIN(sizeof (encp->enc_phy_revision) - 1, MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN)); #if EFSYS_OPT_PHY_LED_CONTROL encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) | (1 << EFX_PHY_LED_OFF) | (1 << EFX_PHY_LED_ON)); #endif /* EFSYS_OPT_PHY_LED_CONTROL */ #if EFSYS_OPT_PHY_PROPS encp->enc_phy_nprops = 0; #endif /* EFSYS_OPT_PHY_PROPS */ /* Get the media type of the fixed port, if recognised. */ EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI); EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4); EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4); EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP); EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS); EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T); EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS); epp->ep_fixed_port_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE); if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES) epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID; epp->ep_phy_cap_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP); #if EFSYS_OPT_PHY_FLAGS encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS); #endif /* EFSYS_OPT_PHY_FLAGS */ encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT); /* Populate internal state */ encp->enc_mcdi_mdio_channel = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL); #if EFSYS_OPT_PHY_STATS encp->enc_mcdi_phy_stat_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK); #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_BIST encp->enc_bist_mask = 0; if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, GET_PHY_CFG_OUT_BIST_CABLE_SHORT)) encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT); if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, GET_PHY_CFG_OUT_BIST_CABLE_LONG)) encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG); if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, GET_PHY_CFG_OUT_BIST)) encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL); #endif /* EFSYS_OPT_BIST */ return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_firmware_update_supported( __in efx_nic_t *enp, __out boolean_t *supportedp) { - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; efx_rc_t rc; if (emcop != NULL) { if ((rc = emcop->emco_feature_supported(enp, EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0) goto fail1; } else { /* Earlier devices always supported updates */ *supportedp = B_TRUE; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_macaddr_change_supported( __in efx_nic_t *enp, __out boolean_t *supportedp) { - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; efx_rc_t rc; if (emcop != NULL) { if ((rc = emcop->emco_feature_supported(enp, EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0) goto fail1; } else { /* Earlier devices always supported MAC changes */ *supportedp = B_TRUE; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_link_control_supported( __in efx_nic_t *enp, __out boolean_t *supportedp) { - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; efx_rc_t rc; if (emcop != NULL) { if ((rc = emcop->emco_feature_supported(enp, EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0) goto fail1; } else { /* Earlier devices always supported link control */ *supportedp = B_TRUE; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_mac_spoofing_supported( __in efx_nic_t *enp, __out boolean_t *supportedp) { - efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; + const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; efx_rc_t rc; if (emcop != NULL) { if ((rc = emcop->emco_feature_supported(enp, EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0) goto fail1; } else { /* Earlier devices always supported MAC spoofing */ *supportedp = B_TRUE; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_BIST #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD /* * Enter bist offline mode. This is a fw mode which puts the NIC into a state * where memory BIST tests can be run and not much else can interfere or happen. * A reboot is required to exit this mode. */ __checkReturn efx_rc_t efx_mcdi_bist_enable_offline( __in efx_nic_t *enp) { efx_mcdi_req_t req; efx_rc_t rc; EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0); EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0); req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST; req.emr_in_buf = NULL; req.emr_in_length = 0; req.emr_out_buf = NULL; req.emr_out_length = 0; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_mcdi_bist_start( __in efx_nic_t *enp, __in efx_bist_type_t type) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN, MC_CMD_START_BIST_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_START_BIST; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_START_BIST_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_START_BIST_OUT_LEN; switch (type) { case EFX_BIST_TYPE_PHY_NORMAL: MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); break; case EFX_BIST_TYPE_PHY_CABLE_SHORT: MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST_CABLE_SHORT); break; case EFX_BIST_TYPE_PHY_CABLE_LONG: MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST_CABLE_LONG); break; case EFX_BIST_TYPE_MC_MEM: MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_MC_MEM_BIST); break; case EFX_BIST_TYPE_SAT_MEM: MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PORT_MEM_BIST); break; case EFX_BIST_TYPE_REG: MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_REG_BIST); break; default: EFSYS_ASSERT(0); } efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_BIST */ /* Enable logging of some events (e.g. link state changes) */ __checkReturn efx_rc_t efx_mcdi_log_ctrl( __in efx_nic_t *enp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN, MC_CMD_LOG_CTRL_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_LOG_CTRL; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN; MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST, MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ); MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_MAC_STATS typedef enum efx_stats_action_e { EFX_STATS_CLEAR, EFX_STATS_UPLOAD, EFX_STATS_ENABLE_NOEVENTS, EFX_STATS_ENABLE_EVENTS, EFX_STATS_DISABLE, } efx_stats_action_t; static __checkReturn efx_rc_t efx_mcdi_mac_stats( __in efx_nic_t *enp, __in_opt efsys_mem_t *esmp, __in efx_stats_action_t action) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN, MC_CMD_MAC_STATS_OUT_DMA_LEN)]; int clear = (action == EFX_STATS_CLEAR); int upload = (action == EFX_STATS_UPLOAD); int enable = (action == EFX_STATS_ENABLE_NOEVENTS); int events = (action == EFX_STATS_ENABLE_EVENTS); int disable = (action == EFX_STATS_DISABLE); efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_MAC_STATS; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN; MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD, MAC_STATS_IN_DMA, upload, MAC_STATS_IN_CLEAR, clear, MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable, MAC_STATS_IN_PERIODIC_ENABLE, enable | events, MAC_STATS_IN_PERIODIC_NOEVENT, !events, MAC_STATS_IN_PERIOD_MS, (enable | events) ? 1000: 0); if (esmp != NULL) { int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t); EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <= EFX_MAC_STATS_SIZE); MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO, EFSYS_MEM_ADDR(esmp) & 0xffffffff); MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI, EFSYS_MEM_ADDR(esmp) >> 32); MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes); } else { EFSYS_ASSERT(!upload && !enable && !events); } /* * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats, * as this may fail (and leave periodic DMA enabled) if the * vadapter has already been deleted. */ MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID, (disable ? EVB_PORT_ID_NULL : enp->en_vport_id)); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { /* EF10: Expect ENOENT if no DMA queues are initialised */ if ((req.emr_rc != ENOENT) || (enp->en_rx_qcount + enp->en_tx_qcount != 0)) { rc = req.emr_rc; goto fail1; } } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_mac_stats_clear( __in efx_nic_t *enp) { efx_rc_t rc; if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_mac_stats_upload( __in efx_nic_t *enp, __in efsys_mem_t *esmp) { efx_rc_t rc; /* * The MC DMAs aggregate statistics for our convenience, so we can * avoid having to pull the statistics buffer into the cache to * maintain cumulative statistics. */ if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_mac_stats_periodic( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __in uint16_t period, __in boolean_t events) { efx_rc_t rc; /* * The MC DMAs aggregate statistics for our convenience, so we can * avoid having to pull the statistics buffer into the cache to * maintain cumulative statistics. * Huntington uses a fixed 1sec period, so use that on Siena too. */ if (period == 0) rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE); else if (events) rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS); else rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS); if (rc != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_MAC_STATS */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD /* * This function returns the pf and vf number of a function. If it is a pf the * vf number is 0xffff. The vf number is the index of the vf on that * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0), * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff). */ __checkReturn efx_rc_t efx_mcdi_get_function_info( __in efx_nic_t *enp, __out uint32_t *pfp, __out_opt uint32_t *vfp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN, MC_CMD_GET_FUNCTION_INFO_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_FUNCTION_INFO; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) { rc = EMSGSIZE; goto fail2; } *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF); if (vfp != NULL) *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_privilege_mask( __in efx_nic_t *enp, __in uint32_t pf, __in uint32_t vf, __out uint32_t *maskp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN, MC_CMD_PRIVILEGE_MASK_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_PRIVILEGE_MASK; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION, PRIVILEGE_MASK_IN_FUNCTION_PF, pf, PRIVILEGE_MASK_IN_FUNCTION_VF, vf); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) { rc = EMSGSIZE; goto fail2; } *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_mcdi_set_workaround( __in efx_nic_t *enp, __in uint32_t type, __in boolean_t enabled, __out_opt uint32_t *flagsp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN, MC_CMD_WORKAROUND_EXT_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_WORKAROUND; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN; MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type); MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0); efx_mcdi_execute_quiet(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (flagsp != NULL) { if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN) *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS); else *flagsp = 0; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_get_workarounds( __in efx_nic_t *enp, __out_opt uint32_t *implementedp, __out_opt uint32_t *enabledp) { efx_mcdi_req_t req; uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_WORKAROUNDS; req.emr_in_buf = NULL; req.emr_in_length = 0; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (implementedp != NULL) { *implementedp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED); } if (enabledp != NULL) { *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED); } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } /* * Size of media information page in accordance with SFF-8472 and SFF-8436. * It is used in MCDI interface as well. */ #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80 static __checkReturn efx_rc_t efx_mcdi_get_phy_media_info( __in efx_nic_t *enp, __in uint32_t mcdi_page, __in uint8_t offset, __in uint8_t len, __out_bcount(len) uint8_t *data) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN, MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN( EFX_PHY_MEDIA_INFO_PAGE_SIZE))]; efx_rc_t rc; EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE); MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used != MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) { rc = EMSGSIZE; goto fail2; } if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) != EFX_PHY_MEDIA_INFO_PAGE_SIZE) { rc = EIO; goto fail3; } memcpy(data, MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset, len); return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } /* * 2-wire device address of the base information in accordance with SFF-8472 * Diagnostic Monitoring Interface for Optical Transceivers section * 4 Memory Organization. */ #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE 0xA0 /* * 2-wire device address of the digital diagnostics monitoring interface * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical * Transceivers section 4 Memory Organization. */ #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM 0xA2 /* * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436 * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and * Operation. */ #define EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP 0xA0 __checkReturn efx_rc_t efx_mcdi_phy_module_get_info( __in efx_nic_t *enp, __in uint8_t dev_addr, __in uint8_t offset, __in uint8_t len, __out_bcount(len) uint8_t *data) { efx_port_t *epp = &(enp->en_port); efx_rc_t rc; uint32_t mcdi_lower_page; uint32_t mcdi_upper_page; EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); /* * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages. * Offset plus length interface allows to access page 0 only. * I.e. non-zero upper pages are not accessible. * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6 * QSFP+ Memory Map for details on how information is structured * and accessible. */ switch (epp->ep_fixed_port_type) { case EFX_PHY_MEDIA_SFP_PLUS: /* * In accordance with SFF-8472 Diagnostic Monitoring * Interface for Optical Transceivers section 4 Memory * Organization two 2-wire addresses are defined. */ switch (dev_addr) { /* Base information */ case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE: /* * MCDI page 0 should be used to access lower * page 0 (0x00 - 0x7f) at the device address 0xA0. */ mcdi_lower_page = 0; /* * MCDI page 1 should be used to access upper * page 0 (0x80 - 0xff) at the device address 0xA0. */ mcdi_upper_page = 1; break; /* Diagnostics */ case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM: /* * MCDI page 2 should be used to access lower * page 0 (0x00 - 0x7f) at the device address 0xA2. */ mcdi_lower_page = 2; /* * MCDI page 3 should be used to access upper * page 0 (0x80 - 0xff) at the device address 0xA2. */ mcdi_upper_page = 3; break; default: rc = ENOTSUP; goto fail1; } break; case EFX_PHY_MEDIA_QSFP_PLUS: switch (dev_addr) { case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP: /* * MCDI page -1 should be used to access lower page 0 * (0x00 - 0x7f). */ mcdi_lower_page = (uint32_t)-1; /* * MCDI page 0 should be used to access upper page 0 * (0x80h - 0xff). */ mcdi_upper_page = 0; break; default: rc = ENOTSUP; goto fail1; } break; default: rc = ENOTSUP; goto fail1; } if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) { uint8_t read_len = MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset); rc = efx_mcdi_get_phy_media_info(enp, mcdi_lower_page, offset, read_len, data); if (rc != 0) goto fail2; data += read_len; len -= read_len; offset = 0; } else { offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE; } if (len > 0) { EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE); EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE); rc = efx_mcdi_get_phy_media_info(enp, mcdi_upper_page, offset, len, data); if (rc != 0) goto fail3; } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_MCDI */ Index: head/sys/dev/sfxge/common/efx_mon.c =================================================================== --- head/sys/dev/sfxge/common/efx_mon.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_mon.c (revision 299517) @@ -1,289 +1,289 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_MON_MCDI #include "mcdi_mon.h" #endif #if EFSYS_OPT_NAMES static const char *__efx_mon_name[] = { "", "nullmon", "lm87", "max6647", "sfx90x0", "sfx91x0" "sfx92x0" }; const char * efx_mon_name( __in efx_nic_t *enp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT(encp->enc_mon_type != EFX_MON_INVALID); EFSYS_ASSERT3U(encp->enc_mon_type, <, EFX_MON_NTYPES); return (__efx_mon_name[encp->enc_mon_type]); } #endif /* EFSYS_OPT_NAMES */ #if EFSYS_OPT_MON_MCDI -static efx_mon_ops_t __efx_mon_mcdi_ops = { +static const efx_mon_ops_t __efx_mon_mcdi_ops = { NULL, /* emo_reset */ NULL, /* emo_reconfigure */ #if EFSYS_OPT_MON_STATS mcdi_mon_stats_update /* emo_stats_update */ #endif /* EFSYS_OPT_MON_STATS */ }; #endif __checkReturn efx_rc_t efx_mon_init( __in efx_nic_t *enp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_mon_t *emp = &(enp->en_mon); - efx_mon_ops_t *emop; + const efx_mon_ops_t *emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); if (enp->en_mod_flags & EFX_MOD_MON) { rc = EINVAL; goto fail1; } enp->en_mod_flags |= EFX_MOD_MON; emp->em_type = encp->enc_mon_type; EFSYS_ASSERT(encp->enc_mon_type != EFX_MON_INVALID); switch (emp->em_type) { #if EFSYS_OPT_MON_MCDI case EFX_MON_SFC90X0: case EFX_MON_SFC91X0: case EFX_MON_SFC92X0: emop = &__efx_mon_mcdi_ops; break; #endif default: rc = ENOTSUP; goto fail2; } if (emop->emo_reset != NULL) { if ((rc = emop->emo_reset(enp)) != 0) goto fail3; } if (emop->emo_reconfigure != NULL) { if ((rc = emop->emo_reconfigure(enp)) != 0) goto fail4; } emp->em_emop = emop; return (0); fail4: EFSYS_PROBE(fail5); if (emop->emo_reset != NULL) (void) emop->emo_reset(enp); fail3: EFSYS_PROBE(fail4); fail2: EFSYS_PROBE(fail3); emp->em_type = EFX_MON_INVALID; enp->en_mod_flags &= ~EFX_MOD_MON; fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_MON_STATS #if EFSYS_OPT_NAMES /* START MKCONFIG GENERATED MonitorStatNamesBlock 31f437eafb0b0437 */ static const char *__mon_stat_name[] = { "value_2_5v", "value_vccp1", "value_vcc", "value_5v", "value_12v", "value_vccp2", "value_ext_temp", "value_int_temp", "value_ain1", "value_ain2", "controller_cooling", "ext_cooling", "1v", "1_2v", "1_8v", "3_3v", "1_2va", "vref", "vaoe", "aoe_temperature", "psu_aoe_temperature", "psu_temperature", "fan0", "fan1", "fan2", "fan3", "fan4", "vaoe_in", "iaoe", "iaoe_in", "nic_power", "0_9v", "i0_9v", "i1_2v", "0_9v_adc", "controller_temperature2", "vreg_temperature", "vreg_0_9v_temperature", "vreg_1_2v_temperature", "int_vptat", "controller_internal_adc_temperature", "ext_vptat", "controller_external_adc_temperature", "ambient_temperature", "airflow", "vdd08d_vss08d_csr", "vdd08d_vss08d_csr_extadc", "hotpoint_temperature", "phy_power_switch_port0", "phy_power_switch_port1", "mum_vcc", "0v9_a", "i0v9_a", "0v9_a_temp", "0v9_b", "i0v9_b", "0v9_b_temp", "ccom_avreg_1v2_supply", "ccom_avreg_1v2_supply_ext_adc", "ccom_avreg_1v8_supply", "ccom_avreg_1v8_supply_ext_adc", "controller_master_vptat", "controller_master_internal_temp", "controller_master_vptat_ext_adc", "controller_master_internal_temp_ext_adc", "controller_slave_vptat", "controller_slave_internal_temp", "controller_slave_vptat_ext_adc", "controller_slave_internal_temp_ext_adc", "sodimm_vout", "sodimm_0_temp", "sodimm_1_temp", "phy0_vcc", "phy1_vcc", "controller_tdiode_temp", "board_front_temp", "board_back_temp", }; /* END MKCONFIG GENERATED MonitorStatNamesBlock */ extern const char * efx_mon_stat_name( __in efx_nic_t *enp, __in efx_mon_stat_t id) { _NOTE(ARGUNUSED(enp)) EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(id, <, EFX_MON_NSTATS); return (__mon_stat_name[id]); } #endif /* EFSYS_OPT_NAMES */ __checkReturn efx_rc_t efx_mon_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_MON_NSTATS) efx_mon_stat_value_t *values) { efx_mon_t *emp = &(enp->en_mon); - efx_mon_ops_t *emop = emp->em_emop; + const efx_mon_ops_t *emop = emp->em_emop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MON); return (emop->emo_stats_update(enp, esmp, values)); } #endif /* EFSYS_OPT_MON_STATS */ void efx_mon_fini( __in efx_nic_t *enp) { efx_mon_t *emp = &(enp->en_mon); - efx_mon_ops_t *emop = emp->em_emop; + const efx_mon_ops_t *emop = emp->em_emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MON); emp->em_emop = NULL; if (emop->emo_reset != NULL) { rc = emop->emo_reset(enp); if (rc != 0) EFSYS_PROBE1(fail1, efx_rc_t, rc); } emp->em_type = EFX_MON_INVALID; enp->en_mod_flags &= ~EFX_MOD_MON; } Index: head/sys/dev/sfxge/common/efx_nic.c =================================================================== --- head/sys/dev/sfxge/common/efx_nic.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_nic.c (revision 299517) @@ -1,968 +1,968 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" __checkReturn efx_rc_t efx_family( __in uint16_t venid, __in uint16_t devid, __out efx_family_t *efp) { if (venid == EFX_PCI_VENID_SFC) { switch (devid) { #if EFSYS_OPT_SIENA case EFX_PCI_DEVID_SIENA_F1_UNINIT: /* * Hardware default for PF0 of uninitialised Siena. * manftest must be able to cope with this device id. */ *efp = EFX_FAMILY_SIENA; return (0); case EFX_PCI_DEVID_BETHPAGE: case EFX_PCI_DEVID_SIENA: *efp = EFX_FAMILY_SIENA; return (0); #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_PCI_DEVID_HUNTINGTON_PF_UNINIT: /* * Hardware default for PF0 of uninitialised Huntington. * manftest must be able to cope with this device id. */ *efp = EFX_FAMILY_HUNTINGTON; return (0); case EFX_PCI_DEVID_FARMINGDALE: case EFX_PCI_DEVID_GREENPORT: *efp = EFX_FAMILY_HUNTINGTON; return (0); case EFX_PCI_DEVID_FARMINGDALE_VF: case EFX_PCI_DEVID_GREENPORT_VF: *efp = EFX_FAMILY_HUNTINGTON; return (0); #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_PCI_DEVID_MEDFORD_PF_UNINIT: /* * Hardware default for PF0 of uninitialised Medford. * manftest must be able to cope with this device id. */ *efp = EFX_FAMILY_MEDFORD; return (0); case EFX_PCI_DEVID_MEDFORD: *efp = EFX_FAMILY_MEDFORD; return (0); case EFX_PCI_DEVID_MEDFORD_VF: *efp = EFX_FAMILY_MEDFORD; return (0); #endif /* EFSYS_OPT_MEDFORD */ case EFX_PCI_DEVID_FALCON: /* Obsolete, not supported */ default: break; } } *efp = EFX_FAMILY_INVALID; return (ENOTSUP); } #define EFX_BIU_MAGIC0 0x01234567 #define EFX_BIU_MAGIC1 0xfedcba98 __checkReturn efx_rc_t efx_nic_biu_test( __in efx_nic_t *enp) { efx_oword_t oword; efx_rc_t rc; /* * Write magic values to scratch registers 0 and 1, then * verify that the values were written correctly. Interleave * the accesses to ensure that the BIU is not just reading * back the cached value that was last written. */ EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { rc = EIO; goto fail1; } EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { rc = EIO; goto fail2; } /* * Perform the same test, with the values swapped. This * ensures that subsequent tests don't start with the correct * values already written into the scratch registers. */ EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC1); EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, EFX_BIU_MAGIC0); EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE); if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC1) { rc = EIO; goto fail3; } EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE); if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != EFX_BIU_MAGIC0) { rc = EIO; goto fail4; } return (0); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_SIENA -static efx_nic_ops_t __efx_nic_siena_ops = { +static const efx_nic_ops_t __efx_nic_siena_ops = { siena_nic_probe, /* eno_probe */ NULL, /* eno_board_cfg */ NULL, /* eno_set_drv_limits */ siena_nic_reset, /* eno_reset */ siena_nic_init, /* eno_init */ NULL, /* eno_get_vi_pool */ NULL, /* eno_get_bar_region */ #if EFSYS_OPT_DIAG siena_nic_register_test, /* eno_register_test */ #endif /* EFSYS_OPT_DIAG */ siena_nic_fini, /* eno_fini */ siena_nic_unprobe, /* eno_unprobe */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON -static efx_nic_ops_t __efx_nic_hunt_ops = { +static const efx_nic_ops_t __efx_nic_hunt_ops = { ef10_nic_probe, /* eno_probe */ hunt_board_cfg, /* eno_board_cfg */ ef10_nic_set_drv_limits, /* eno_set_drv_limits */ ef10_nic_reset, /* eno_reset */ ef10_nic_init, /* eno_init */ ef10_nic_get_vi_pool, /* eno_get_vi_pool */ ef10_nic_get_bar_region, /* eno_get_bar_region */ #if EFSYS_OPT_DIAG ef10_nic_register_test, /* eno_register_test */ #endif /* EFSYS_OPT_DIAG */ ef10_nic_fini, /* eno_fini */ ef10_nic_unprobe, /* eno_unprobe */ }; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD -static efx_nic_ops_t __efx_nic_medford_ops = { +static const efx_nic_ops_t __efx_nic_medford_ops = { ef10_nic_probe, /* eno_probe */ medford_board_cfg, /* eno_board_cfg */ ef10_nic_set_drv_limits, /* eno_set_drv_limits */ ef10_nic_reset, /* eno_reset */ ef10_nic_init, /* eno_init */ ef10_nic_get_vi_pool, /* eno_get_vi_pool */ ef10_nic_get_bar_region, /* eno_get_bar_region */ #if EFSYS_OPT_DIAG ef10_nic_register_test, /* eno_register_test */ #endif /* EFSYS_OPT_DIAG */ ef10_nic_fini, /* eno_fini */ ef10_nic_unprobe, /* eno_unprobe */ }; #endif /* EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_nic_create( __in efx_family_t family, __in efsys_identifier_t *esip, __in efsys_bar_t *esbp, __in efsys_lock_t *eslp, __deref_out efx_nic_t **enpp) { efx_nic_t *enp; efx_rc_t rc; EFSYS_ASSERT3U(family, >, EFX_FAMILY_INVALID); EFSYS_ASSERT3U(family, <, EFX_FAMILY_NTYPES); /* Allocate a NIC object */ EFSYS_KMEM_ALLOC(esip, sizeof (efx_nic_t), enp); if (enp == NULL) { rc = ENOMEM; goto fail1; } enp->en_magic = EFX_NIC_MAGIC; switch (family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - enp->en_enop = (efx_nic_ops_t *)&__efx_nic_siena_ops; + enp->en_enop = &__efx_nic_siena_ops; enp->en_features = EFX_FEATURE_IPV6 | EFX_FEATURE_LFSR_HASH_INSERT | EFX_FEATURE_LINK_EVENTS | EFX_FEATURE_PERIODIC_MAC_STATS | EFX_FEATURE_WOL | EFX_FEATURE_MCDI | EFX_FEATURE_LOOKAHEAD_SPLIT | EFX_FEATURE_MAC_HEADER_FILTERS | EFX_FEATURE_TX_SRC_FILTERS; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - enp->en_enop = (efx_nic_ops_t *)&__efx_nic_hunt_ops; + enp->en_enop = &__efx_nic_hunt_ops; /* FIXME: Add WOL support */ enp->en_features = EFX_FEATURE_IPV6 | EFX_FEATURE_LINK_EVENTS | EFX_FEATURE_PERIODIC_MAC_STATS | EFX_FEATURE_MCDI | EFX_FEATURE_MAC_HEADER_FILTERS | EFX_FEATURE_MCDI_DMA | EFX_FEATURE_PIO_BUFFERS | EFX_FEATURE_FW_ASSISTED_TSO | EFX_FEATURE_FW_ASSISTED_TSO_V2; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - enp->en_enop = (efx_nic_ops_t *)&__efx_nic_medford_ops; + enp->en_enop = &__efx_nic_medford_ops; /* * FW_ASSISTED_TSO omitted as Medford only supports firmware * assisted TSO version 2, not the v1 scheme used on Huntington. */ enp->en_features = EFX_FEATURE_IPV6 | EFX_FEATURE_LINK_EVENTS | EFX_FEATURE_PERIODIC_MAC_STATS | EFX_FEATURE_MCDI | EFX_FEATURE_MAC_HEADER_FILTERS | EFX_FEATURE_MCDI_DMA | EFX_FEATURE_PIO_BUFFERS; break; #endif /* EFSYS_OPT_MEDFORD */ default: rc = ENOTSUP; goto fail2; } enp->en_family = family; enp->en_esip = esip; enp->en_esbp = esbp; enp->en_eslp = eslp; *enpp = enp; return (0); fail2: EFSYS_PROBE(fail2); enp->en_magic = 0; /* Free the NIC object */ EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nic_probe( __in efx_nic_t *enp) { - efx_nic_ops_t *enop; + const efx_nic_ops_t *enop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); #if EFSYS_OPT_MCDI EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); #endif /* EFSYS_OPT_MCDI */ EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_PROBE)); enop = enp->en_enop; if ((rc = enop->eno_probe(enp)) != 0) goto fail1; if ((rc = efx_phy_probe(enp)) != 0) goto fail2; enp->en_mod_flags |= EFX_MOD_PROBE; return (0); fail2: EFSYS_PROBE(fail2); enop->eno_unprobe(enp); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nic_set_drv_limits( __inout efx_nic_t *enp, __in efx_drv_limits_t *edlp) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); if (enop->eno_set_drv_limits != NULL) { if ((rc = enop->eno_set_drv_limits(enp, edlp)) != 0) goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nic_get_bar_region( __in efx_nic_t *enp, __in efx_nic_region_t region, __out uint32_t *offsetp, __out size_t *sizep) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); if (enop->eno_get_bar_region == NULL) { rc = ENOTSUP; goto fail1; } if ((rc = (enop->eno_get_bar_region)(enp, region, offsetp, sizep)) != 0) { goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nic_get_vi_pool( __in efx_nic_t *enp, __out uint32_t *evq_countp, __out uint32_t *rxq_countp, __out uint32_t *txq_countp) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; efx_nic_cfg_t *encp = &enp->en_nic_cfg; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); if (enop->eno_get_vi_pool != NULL) { uint32_t vi_count = 0; if ((rc = (enop->eno_get_vi_pool)(enp, &vi_count)) != 0) goto fail1; *evq_countp = vi_count; *rxq_countp = vi_count; *txq_countp = vi_count; } else { /* Use NIC limits as default value */ *evq_countp = encp->enc_evq_limit; *rxq_countp = encp->enc_rxq_limit; *txq_countp = encp->enc_txq_limit; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nic_init( __in efx_nic_t *enp) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); if (enp->en_mod_flags & EFX_MOD_NIC) { rc = EINVAL; goto fail1; } if ((rc = enop->eno_init(enp)) != 0) goto fail2; enp->en_mod_flags |= EFX_MOD_NIC; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_nic_fini( __in efx_nic_t *enp) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_NIC); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); enop->eno_fini(enp); enp->en_mod_flags &= ~EFX_MOD_NIC; } void efx_nic_unprobe( __in efx_nic_t *enp) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); #if EFSYS_OPT_MCDI EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); #endif /* EFSYS_OPT_MCDI */ EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_INTR)); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); efx_phy_unprobe(enp); enop->eno_unprobe(enp); enp->en_mod_flags &= ~EFX_MOD_PROBE; } void efx_nic_destroy( __in efx_nic_t *enp) { efsys_identifier_t *esip = enp->en_esip; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); enp->en_family = 0; enp->en_esip = NULL; enp->en_esbp = NULL; enp->en_eslp = NULL; enp->en_enop = NULL; enp->en_magic = 0; /* Free the NIC object */ EFSYS_KMEM_FREE(esip, sizeof (efx_nic_t), enp); } __checkReturn efx_rc_t efx_nic_reset( __in efx_nic_t *enp) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; unsigned int mod_flags; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); /* * All modules except the MCDI, PROBE, NVRAM, VPD, MON, LIC * (which we do not reset here) must have been shut down or never * initialized. * * A rule of thumb here is: If the controller or MC reboots, is *any* * state lost. If it's lost and needs reapplying, then the module * *must* not be initialised during the reset. */ mod_flags = enp->en_mod_flags; mod_flags &= ~(EFX_MOD_MCDI | EFX_MOD_PROBE | EFX_MOD_NVRAM | EFX_MOD_VPD | EFX_MOD_MON | EFX_MOD_LIC); EFSYS_ASSERT3U(mod_flags, ==, 0); if (mod_flags != 0) { rc = EINVAL; goto fail1; } if ((rc = enop->eno_reset(enp)) != 0) goto fail2; enp->en_reset_flags |= EFX_RESET_MAC; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } const efx_nic_cfg_t * efx_nic_cfg_get( __in efx_nic_t *enp) { EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); return (&(enp->en_nic_cfg)); } #if EFSYS_OPT_DIAG __checkReturn efx_rc_t efx_nic_register_test( __in efx_nic_t *enp) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); if ((rc = enop->eno_register_test(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nic_test_registers( __in efx_nic_t *enp, __in efx_register_set_t *rsp, __in size_t count) { unsigned int bit; efx_oword_t original; efx_oword_t reg; efx_oword_t buf; efx_rc_t rc; while (count > 0) { /* This function is only suitable for registers */ EFSYS_ASSERT(rsp->rows == 1); /* bit sweep on and off */ EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original, B_TRUE); for (bit = 0; bit < 128; bit++) { /* Is this bit in the mask? */ if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit)) continue; /* Test this bit can be set in isolation */ reg = original; EFX_AND_OWORD(reg, rsp->mask); EFX_SET_OWORD_BIT(reg, bit); EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, B_TRUE); EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, B_TRUE); EFX_AND_OWORD(buf, rsp->mask); if (memcmp(®, &buf, sizeof (reg))) { rc = EIO; goto fail1; } /* Test this bit can be cleared in isolation */ EFX_OR_OWORD(reg, rsp->mask); EFX_CLEAR_OWORD_BIT(reg, bit); EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, ®, B_TRUE); EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf, B_TRUE); EFX_AND_OWORD(buf, rsp->mask); if (memcmp(®, &buf, sizeof (reg))) { rc = EIO; goto fail2; } } /* Restore the old value */ EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE); --count; ++rsp; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); /* Restore the old value */ EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE); return (rc); } __checkReturn efx_rc_t efx_nic_test_tables( __in efx_nic_t *enp, __in efx_register_set_t *rsp, __in efx_pattern_type_t pattern, __in size_t count) { efx_sram_pattern_fn_t func; unsigned int index; unsigned int address; efx_oword_t reg; efx_oword_t buf; efx_rc_t rc; EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES); func = __efx_sram_pattern_fns[pattern]; while (count > 0) { /* Write */ address = rsp->address; for (index = 0; index < rsp->rows; ++index) { func(2 * index + 0, B_FALSE, ®.eo_qword[0]); func(2 * index + 1, B_FALSE, ®.eo_qword[1]); EFX_AND_OWORD(reg, rsp->mask); EFSYS_BAR_WRITEO(enp->en_esbp, address, ®, B_TRUE); address += rsp->step; } /* Read */ address = rsp->address; for (index = 0; index < rsp->rows; ++index) { func(2 * index + 0, B_FALSE, ®.eo_qword[0]); func(2 * index + 1, B_FALSE, ®.eo_qword[1]); EFX_AND_OWORD(reg, rsp->mask); EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE); if (memcmp(®, &buf, sizeof (reg))) { rc = EIO; goto fail1; } address += rsp->step; } ++rsp; --count; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_DIAG */ #if EFSYS_OPT_LOOPBACK extern void efx_loopback_mask( __in efx_loopback_kind_t loopback_kind, __out efx_qword_t *maskp) { efx_qword_t mask; EFSYS_ASSERT3U(loopback_kind, <, EFX_LOOPBACK_NKINDS); EFSYS_ASSERT(maskp != NULL); /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XPORT == EFX_LOOPBACK_XPORT); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII_WS == EFX_LOOPBACK_XGMII_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS == EFX_LOOPBACK_XAUI_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_FAR == EFX_LOOPBACK_XAUI_WS_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_WS_NEAR == EFX_LOOPBACK_XAUI_WS_NEAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_WS == EFX_LOOPBACK_GMII_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS == EFX_LOOPBACK_XFI_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_WS_FAR == EFX_LOOPBACK_XFI_WS_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS_WS == EFX_LOOPBACK_PHYXS_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT == EFX_LOOPBACK_PMA_INT); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_NEAR == EFX_LOOPBACK_SD_NEAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FAR == EFX_LOOPBACK_SD_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMA_INT_WS == EFX_LOOPBACK_PMA_INT_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP2_WS == EFX_LOOPBACK_SD_FEP2_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP1_5_WS == EFX_LOOPBACK_SD_FEP1_5_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FEP_WS == EFX_LOOPBACK_SD_FEP_WS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SD_FES_WS == EFX_LOOPBACK_SD_FES_WS); /* Build bitmask of possible loopback types */ EFX_ZERO_QWORD(mask); if ((loopback_kind == EFX_LOOPBACK_KIND_OFF) || (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_OFF); } if ((loopback_kind == EFX_LOOPBACK_KIND_MAC) || (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { /* * The "MAC" grouping has historically been used by drivers to * mean loopbacks supported by on-chip hardware. Keep that * meaning here, and include on-chip PHY layer loopbacks. */ EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_DATA); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMAC); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGMII); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGXS); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XGBR); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XAUI_FAR); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GMII_FAR); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SGMII_FAR); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_XFI_FAR); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_INT); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_NEAR); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_SD_FAR); } if ((loopback_kind == EFX_LOOPBACK_KIND_PHY) || (loopback_kind == EFX_LOOPBACK_KIND_ALL)) { /* * The "PHY" grouping has historically been used by drivers to * mean loopbacks supported by off-chip hardware. Keep that * meaning here. */ EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_GPHY); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PHY_XS); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PCS); EFX_SET_QWORD_BIT(mask, EFX_LOOPBACK_PMA_PMD); } *maskp = mask; } __checkReturn efx_rc_t efx_mcdi_get_loopback_modes( __in efx_nic_t *enp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_LOOPBACK_MODES_IN_LEN, MC_CMD_GET_LOOPBACK_MODES_OUT_LEN)]; efx_qword_t mask; efx_qword_t modes; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_LOOPBACK_MODES; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_LOOPBACK_MODES_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_LOOPBACK_MODES_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_OFST + MC_CMD_GET_LOOPBACK_MODES_OUT_SUGGESTED_LEN) { rc = EMSGSIZE; goto fail2; } /* * We assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespaces agree * in efx_loopback_mask() and in siena_phy.c:siena_phy_get_link(). */ efx_loopback_mask(EFX_LOOPBACK_KIND_ALL, &mask); EFX_AND_QWORD(mask, *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_SUGGESTED)); modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_100M); EFX_AND_QWORD(modes, mask); encp->enc_loopback_types[EFX_LINK_100FDX] = modes; modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_1G); EFX_AND_QWORD(modes, mask); encp->enc_loopback_types[EFX_LINK_1000FDX] = modes; modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_10G); EFX_AND_QWORD(modes, mask); encp->enc_loopback_types[EFX_LINK_10000FDX] = modes; if (req.emr_out_length_used >= MC_CMD_GET_LOOPBACK_MODES_OUT_40G_OFST + MC_CMD_GET_LOOPBACK_MODES_OUT_40G_LEN) { /* Response includes 40G loopback modes */ modes = *MCDI_OUT2(req, efx_qword_t, GET_LOOPBACK_MODES_OUT_40G); EFX_AND_QWORD(modes, mask); encp->enc_loopback_types[EFX_LINK_40000FDX] = modes; } EFX_ZERO_QWORD(modes); EFX_SET_QWORD_BIT(modes, EFX_LOOPBACK_OFF); EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_100FDX]); EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_1000FDX]); EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_10000FDX]); EFX_OR_QWORD(modes, encp->enc_loopback_types[EFX_LINK_40000FDX]); encp->enc_loopback_types[EFX_LINK_UNKNOWN] = modes; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_LOOPBACK */ Index: head/sys/dev/sfxge/common/efx_nvram.c =================================================================== --- head/sys/dev/sfxge/common/efx_nvram.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_nvram.c (revision 299517) @@ -1,983 +1,983 @@ /*- * Copyright (c) 2009-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_NVRAM #if EFSYS_OPT_SIENA -static efx_nvram_ops_t __efx_nvram_siena_ops = { +static const efx_nvram_ops_t __efx_nvram_siena_ops = { #if EFSYS_OPT_DIAG siena_nvram_test, /* envo_test */ #endif /* EFSYS_OPT_DIAG */ siena_nvram_type_to_partn, /* envo_type_to_partn */ siena_nvram_partn_size, /* envo_partn_size */ siena_nvram_partn_rw_start, /* envo_partn_rw_start */ siena_nvram_partn_read, /* envo_partn_read */ siena_nvram_partn_erase, /* envo_partn_erase */ siena_nvram_partn_write, /* envo_partn_write */ siena_nvram_partn_rw_finish, /* envo_partn_rw_finish */ siena_nvram_partn_get_version, /* envo_partn_get_version */ siena_nvram_partn_set_version, /* envo_partn_set_version */ NULL, /* envo_partn_validate */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_nvram_ops_t __efx_nvram_ef10_ops = { +static const efx_nvram_ops_t __efx_nvram_ef10_ops = { #if EFSYS_OPT_DIAG ef10_nvram_test, /* envo_test */ #endif /* EFSYS_OPT_DIAG */ ef10_nvram_type_to_partn, /* envo_type_to_partn */ ef10_nvram_partn_size, /* envo_partn_size */ ef10_nvram_partn_rw_start, /* envo_partn_rw_start */ ef10_nvram_partn_read, /* envo_partn_read */ ef10_nvram_partn_erase, /* envo_partn_erase */ ef10_nvram_partn_write, /* envo_partn_write */ ef10_nvram_partn_rw_finish, /* envo_partn_rw_finish */ ef10_nvram_partn_get_version, /* envo_partn_get_version */ ef10_nvram_partn_set_version, /* envo_partn_set_version */ ef10_nvram_buffer_validate, /* envo_buffer_validate */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_nvram_init( __in efx_nic_t *enp) { - efx_nvram_ops_t *envop; + const efx_nvram_ops_t *envop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NVRAM)); switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - envop = (efx_nvram_ops_t *)&__efx_nvram_siena_ops; + envop = &__efx_nvram_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - envop = (efx_nvram_ops_t *)&__efx_nvram_ef10_ops; + envop = &__efx_nvram_ef10_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - envop = (efx_nvram_ops_t *)&__efx_nvram_ef10_ops; + envop = &__efx_nvram_ef10_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail1; } enp->en_envop = envop; enp->en_mod_flags |= EFX_MOD_NVRAM; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_DIAG __checkReturn efx_rc_t efx_nvram_test( __in efx_nic_t *enp) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); if ((rc = envop->envo_test(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_DIAG */ __checkReturn efx_rc_t efx_nvram_size( __in efx_nic_t *enp, __in efx_nvram_type_t type, __out size_t *sizep) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) goto fail1; if ((rc = envop->envo_partn_size(enp, partn, sizep)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); *sizep = 0; return (rc); } __checkReturn efx_rc_t efx_nvram_get_version( __in efx_nic_t *enp, __in efx_nvram_type_t type, __out uint32_t *subtypep, __out_ecount(4) uint16_t version[4]) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) goto fail1; if ((rc = envop->envo_partn_get_version(enp, partn, subtypep, version)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nvram_rw_start( __in efx_nic_t *enp, __in efx_nvram_type_t type, __out_opt size_t *chunk_sizep) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) goto fail1; if ((rc = envop->envo_partn_rw_start(enp, partn, chunk_sizep)) != 0) goto fail2; enp->en_nvram_locked = type; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nvram_read_chunk( __in efx_nic_t *enp, __in efx_nvram_type_t type, __in unsigned int offset, __out_bcount(size) caddr_t data, __in size_t size) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) goto fail1; if ((rc = envop->envo_partn_read(enp, partn, offset, data, size)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nvram_erase( __in efx_nic_t *enp, __in efx_nvram_type_t type) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; unsigned int offset = 0; size_t size = 0; uint32_t partn; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) goto fail1; if ((rc = envop->envo_partn_size(enp, partn, &size)) != 0) goto fail2; if ((rc = envop->envo_partn_erase(enp, partn, offset, size)) != 0) goto fail3; return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_nvram_write_chunk( __in efx_nic_t *enp, __in efx_nvram_type_t type, __in unsigned int offset, __in_bcount(size) caddr_t data, __in size_t size) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) goto fail1; if ((rc = envop->envo_partn_write(enp, partn, offset, data, size)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_nvram_rw_finish( __in efx_nic_t *enp, __in efx_nvram_type_t type) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); EFSYS_ASSERT3U(type, !=, EFX_NVRAM_INVALID); EFSYS_ASSERT3U(enp->en_nvram_locked, ==, type); if (envop->envo_type_to_partn(enp, type, &partn) == 0) envop->envo_partn_rw_finish(enp, partn); enp->en_nvram_locked = EFX_NVRAM_INVALID; } __checkReturn efx_rc_t efx_nvram_set_version( __in efx_nic_t *enp, __in efx_nvram_type_t type, __in_ecount(4) uint16_t version[4]) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); /* * The Siena implementation of envo_set_version() will attempt to * acquire the NVRAM_UPDATE lock for the DYNAMIC_CONFIG sector. * Therefore, you can't have already acquired the NVRAM_UPDATE lock. */ EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) goto fail1; if ((rc = envop->envo_partn_set_version(enp, partn, version)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } /* Validate buffer contents (before writing to flash) */ __checkReturn efx_rc_t efx_nvram_validate( __in efx_nic_t *enp, __in efx_nvram_type_t type, __in_bcount(partn_size) caddr_t partn_data, __in size_t partn_size) { - efx_nvram_ops_t *envop = enp->en_envop; + const efx_nvram_ops_t *envop = enp->en_envop; uint32_t partn; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(type, <, EFX_NVRAM_NTYPES); if ((rc = envop->envo_type_to_partn(enp, type, &partn)) != 0) goto fail1; if (envop->envo_type_to_partn != NULL && ((rc = envop->envo_buffer_validate(enp, partn, partn_data, partn_size)) != 0)) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_nvram_fini( __in efx_nic_t *enp) { EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NVRAM); EFSYS_ASSERT3U(enp->en_nvram_locked, ==, EFX_NVRAM_INVALID); enp->en_envop = NULL; enp->en_mod_flags &= ~EFX_MOD_NVRAM; } #endif /* EFSYS_OPT_NVRAM */ #if EFSYS_OPT_NVRAM || EFSYS_OPT_VPD /* * Internal MCDI request handling */ __checkReturn efx_rc_t efx_mcdi_nvram_partitions( __in efx_nic_t *enp, __out_bcount(size) caddr_t data, __in size_t size, __out unsigned int *npartnp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_NVRAM_PARTITIONS_IN_LEN, MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX)]; unsigned int npartn; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_PARTITIONS; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_PARTITIONS_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_PARTITIONS_OUT_LENMAX; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LENMIN) { rc = EMSGSIZE; goto fail2; } npartn = MCDI_OUT_DWORD(req, NVRAM_PARTITIONS_OUT_NUM_PARTITIONS); if (req.emr_out_length_used < MC_CMD_NVRAM_PARTITIONS_OUT_LEN(npartn)) { rc = ENOENT; goto fail3; } if (size < npartn * sizeof (uint32_t)) { rc = ENOSPC; goto fail3; } *npartnp = npartn; memcpy(data, MCDI_OUT2(req, uint32_t, NVRAM_PARTITIONS_OUT_TYPE_ID), (npartn * sizeof (uint32_t))); return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_nvram_metadata( __in efx_nic_t *enp, __in uint32_t partn, __out uint32_t *subtypep, __out_ecount(4) uint16_t version[4], __out_bcount_opt(size) char *descp, __in size_t size) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_NVRAM_METADATA_IN_LEN, MC_CMD_NVRAM_METADATA_OUT_LENMAX)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_METADATA; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_METADATA_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_METADATA_OUT_LENMAX; MCDI_IN_SET_DWORD(req, NVRAM_METADATA_IN_TYPE, partn); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_NVRAM_METADATA_OUT_LENMIN) { rc = EMSGSIZE; goto fail2; } if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, NVRAM_METADATA_OUT_SUBTYPE_VALID)) { *subtypep = MCDI_OUT_DWORD(req, NVRAM_METADATA_OUT_SUBTYPE); } else { *subtypep = 0; } if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, NVRAM_METADATA_OUT_VERSION_VALID)) { version[0] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_W); version[1] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_X); version[2] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Y); version[3] = MCDI_OUT_WORD(req, NVRAM_METADATA_OUT_VERSION_Z); } else { version[0] = version[1] = version[2] = version[3] = 0; } if (MCDI_OUT_DWORD_FIELD(req, NVRAM_METADATA_OUT_FLAGS, NVRAM_METADATA_OUT_DESCRIPTION_VALID)) { /* Return optional descrition string */ if ((descp != NULL) && (size > 0)) { size_t desclen; descp[0] = '\0'; desclen = (req.emr_out_length_used - MC_CMD_NVRAM_METADATA_OUT_LEN(0)); EFSYS_ASSERT3U(desclen, <=, MC_CMD_NVRAM_METADATA_OUT_DESCRIPTION_MAXNUM); if (size < desclen) { rc = ENOSPC; goto fail3; } memcpy(descp, MCDI_OUT2(req, char, NVRAM_METADATA_OUT_DESCRIPTION), desclen); /* Ensure string is NUL terminated */ descp[desclen] = '\0'; } } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_nvram_info( __in efx_nic_t *enp, __in uint32_t partn, __out_opt size_t *sizep, __out_opt uint32_t *addressp, __out_opt uint32_t *erase_sizep, __out_opt uint32_t *write_sizep) { uint8_t payload[MAX(MC_CMD_NVRAM_INFO_IN_LEN, MC_CMD_NVRAM_INFO_V2_OUT_LEN)]; efx_mcdi_req_t req; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_INFO; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_INFO_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_INFO_V2_OUT_LEN; MCDI_IN_SET_DWORD(req, NVRAM_INFO_IN_TYPE, partn); efx_mcdi_execute_quiet(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_NVRAM_INFO_OUT_LEN) { rc = EMSGSIZE; goto fail2; } if (sizep) *sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_SIZE); if (addressp) *addressp = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_PHYSADDR); if (erase_sizep) *erase_sizep = MCDI_OUT_DWORD(req, NVRAM_INFO_OUT_ERASESIZE); if (write_sizep) { *write_sizep = (req.emr_out_length_used < MC_CMD_NVRAM_INFO_V2_OUT_LEN) ? 0 : MCDI_OUT_DWORD(req, NVRAM_INFO_V2_OUT_WRITESIZE); } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_nvram_update_start( __in efx_nic_t *enp, __in uint32_t partn) { uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_START_IN_LEN, MC_CMD_NVRAM_UPDATE_START_OUT_LEN)]; efx_mcdi_req_t req; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_UPDATE_START; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_UPDATE_START_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_UPDATE_START_OUT_LEN; MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_START_IN_TYPE, partn); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_nvram_read( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t offset, __out_bcount(size) caddr_t data, __in size_t size, __in uint32_t mode) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_NVRAM_READ_IN_V2_LEN, MC_CMD_NVRAM_READ_OUT_LENMAX)]; efx_rc_t rc; if (size > MC_CMD_NVRAM_READ_OUT_LENMAX) { rc = EINVAL; goto fail1; } (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_READ; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_READ_IN_V2_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_READ_OUT_LENMAX; MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_TYPE, partn); MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_OFFSET, offset); MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_LENGTH, size); MCDI_IN_SET_DWORD(req, NVRAM_READ_IN_V2_MODE, mode); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_NVRAM_READ_OUT_LEN(size)) { rc = EMSGSIZE; goto fail2; } memcpy(data, MCDI_OUT2(req, uint8_t, NVRAM_READ_OUT_READ_BUFFER), size); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_nvram_erase( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t offset, __in size_t size) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_NVRAM_ERASE_IN_LEN, MC_CMD_NVRAM_ERASE_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_ERASE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_ERASE_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_ERASE_OUT_LEN; MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_TYPE, partn); MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_OFFSET, offset); MCDI_IN_SET_DWORD(req, NVRAM_ERASE_IN_LENGTH, size); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } /* * The NVRAM_WRITE MCDI command is a V1 command and so is supported by both * Sienna and EF10 based boards. However EF10 based boards support the use * of this command with payloads up to the maximum MCDI V2 payload length. */ __checkReturn efx_rc_t efx_mcdi_nvram_write( __in efx_nic_t *enp, __in uint32_t partn, __in uint32_t offset, __out_bcount(size) caddr_t data, __in size_t size) { efx_mcdi_req_t req; uint8_t payload[MAX(MCDI_CTL_SDU_LEN_MAX_V1, MCDI_CTL_SDU_LEN_MAX_V2)]; efx_rc_t rc; size_t max_data_size; max_data_size = enp->en_nic_cfg.enc_mcdi_max_payload_length - MC_CMD_NVRAM_WRITE_IN_LEN(0); EFSYS_ASSERT3U(enp->en_nic_cfg.enc_mcdi_max_payload_length, >, 0); EFSYS_ASSERT3U(max_data_size, <, enp->en_nic_cfg.enc_mcdi_max_payload_length); if (size > max_data_size) { rc = EINVAL; goto fail1; } (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_WRITE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_WRITE_IN_LEN(size); req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_WRITE_OUT_LEN; MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_TYPE, partn); MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_OFFSET, offset); MCDI_IN_SET_DWORD(req, NVRAM_WRITE_IN_LENGTH, size); memcpy(MCDI_IN2(req, uint8_t, NVRAM_WRITE_IN_WRITE_BUFFER), data, size); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_nvram_update_finish( __in efx_nic_t *enp, __in uint32_t partn, __in boolean_t reboot) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN, MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_UPDATE_FINISH; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_UPDATE_FINISH_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_UPDATE_FINISH_OUT_LEN; MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_TYPE, partn); MCDI_IN_SET_DWORD(req, NVRAM_UPDATE_FINISH_IN_REBOOT, reboot); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_DIAG __checkReturn efx_rc_t efx_mcdi_nvram_test( __in efx_nic_t *enp, __in uint32_t partn) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_NVRAM_TEST_IN_LEN, MC_CMD_NVRAM_TEST_OUT_LEN)]; int result; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_TEST; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_TEST_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_TEST_OUT_LEN; MCDI_IN_SET_DWORD(req, NVRAM_TEST_IN_TYPE, partn); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_NVRAM_TEST_OUT_LEN) { rc = EMSGSIZE; goto fail2; } result = MCDI_OUT_DWORD(req, NVRAM_TEST_OUT_RESULT); if (result == MC_CMD_NVRAM_TEST_FAIL) { EFSYS_PROBE1(nvram_test_failure, int, partn); rc = (EINVAL); goto fail3; } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_DIAG */ #endif /* EFSYS_OPT_NVRAM || EFSYS_OPT_VPD */ Index: head/sys/dev/sfxge/common/efx_phy.c =================================================================== --- head/sys/dev/sfxge/common/efx_phy.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_phy.c (revision 299517) @@ -1,632 +1,632 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_SIENA -static efx_phy_ops_t __efx_phy_siena_ops = { +static const efx_phy_ops_t __efx_phy_siena_ops = { siena_phy_power, /* epo_power */ NULL, /* epo_reset */ siena_phy_reconfigure, /* epo_reconfigure */ siena_phy_verify, /* epo_verify */ NULL, /* epo_uplink_check */ NULL, /* epo_downlink_check */ siena_phy_oui_get, /* epo_oui_get */ #if EFSYS_OPT_PHY_STATS siena_phy_stats_update, /* epo_stats_update */ #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_PHY_PROPS #if EFSYS_OPT_NAMES siena_phy_prop_name, /* epo_prop_name */ #endif siena_phy_prop_get, /* epo_prop_get */ siena_phy_prop_set, /* epo_prop_set */ #endif /* EFSYS_OPT_PHY_PROPS */ #if EFSYS_OPT_BIST NULL, /* epo_bist_enable_offline */ siena_phy_bist_start, /* epo_bist_start */ siena_phy_bist_poll, /* epo_bist_poll */ siena_phy_bist_stop, /* epo_bist_stop */ #endif /* EFSYS_OPT_BIST */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_phy_ops_t __efx_phy_ef10_ops = { +static const efx_phy_ops_t __efx_phy_ef10_ops = { ef10_phy_power, /* epo_power */ NULL, /* epo_reset */ ef10_phy_reconfigure, /* epo_reconfigure */ ef10_phy_verify, /* epo_verify */ NULL, /* epo_uplink_check */ NULL, /* epo_downlink_check */ ef10_phy_oui_get, /* epo_oui_get */ #if EFSYS_OPT_PHY_STATS ef10_phy_stats_update, /* epo_stats_update */ #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_PHY_PROPS #if EFSYS_OPT_NAMES ef10_phy_prop_name, /* epo_prop_name */ #endif ef10_phy_prop_get, /* epo_prop_get */ ef10_phy_prop_set, /* epo_prop_set */ #endif /* EFSYS_OPT_PHY_PROPS */ #if EFSYS_OPT_BIST /* FIXME: Are these BIST methods appropriate for Medford? */ hunt_bist_enable_offline, /* epo_bist_enable_offline */ hunt_bist_start, /* epo_bist_start */ hunt_bist_poll, /* epo_bist_poll */ hunt_bist_stop, /* epo_bist_stop */ #endif /* EFSYS_OPT_BIST */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_phy_probe( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_phy_ops_t *epop; + const efx_phy_ops_t *epop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); epp->ep_port = encp->enc_port; epp->ep_phy_type = encp->enc_phy_type; /* Hook in operations structure */ switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - epop = (efx_phy_ops_t *)&__efx_phy_siena_ops; + epop = &__efx_phy_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - epop = (efx_phy_ops_t *)&__efx_phy_ef10_ops; + epop = &__efx_phy_ef10_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - epop = (efx_phy_ops_t *)&__efx_phy_ef10_ops; + epop = &__efx_phy_ef10_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: rc = ENOTSUP; goto fail1; } epp->ep_epop = epop; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); epp->ep_port = 0; epp->ep_phy_type = 0; return (rc); } __checkReturn efx_rc_t efx_phy_verify( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); return (epop->epo_verify(enp)); } #if EFSYS_OPT_PHY_LED_CONTROL __checkReturn efx_rc_t efx_phy_led_set( __in efx_nic_t *enp, __in efx_phy_led_mode_t mode) { efx_nic_cfg_t *encp = (&enp->en_nic_cfg); efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; uint32_t mask; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if (epp->ep_phy_led_mode == mode) goto done; mask = (1 << EFX_PHY_LED_DEFAULT); mask |= encp->enc_led_mask; if (!((1 << mode) & mask)) { rc = ENOTSUP; goto fail1; } EFSYS_ASSERT3U(mode, <, EFX_PHY_LED_NMODES); epp->ep_phy_led_mode = mode; if ((rc = epop->epo_reconfigure(enp)) != 0) goto fail2; done: return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_PHY_LED_CONTROL */ void efx_phy_adv_cap_get( __in efx_nic_t *enp, __in uint32_t flag, __out uint32_t *maskp) { efx_port_t *epp = &(enp->en_port); EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); switch (flag) { case EFX_PHY_CAP_CURRENT: *maskp = epp->ep_adv_cap_mask; break; case EFX_PHY_CAP_DEFAULT: *maskp = epp->ep_default_adv_cap_mask; break; case EFX_PHY_CAP_PERM: *maskp = epp->ep_phy_cap_mask; break; default: EFSYS_ASSERT(B_FALSE); break; } } __checkReturn efx_rc_t efx_phy_adv_cap_set( __in efx_nic_t *enp, __in uint32_t mask) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; uint32_t old_mask; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if ((mask & ~epp->ep_phy_cap_mask) != 0) { rc = ENOTSUP; goto fail1; } if (epp->ep_adv_cap_mask == mask) goto done; old_mask = epp->ep_adv_cap_mask; epp->ep_adv_cap_mask = mask; if ((rc = epop->epo_reconfigure(enp)) != 0) goto fail2; done: return (0); fail2: EFSYS_PROBE(fail2); epp->ep_adv_cap_mask = old_mask; /* Reconfigure for robustness */ if (epop->epo_reconfigure(enp) != 0) { /* * We may have an inconsistent view of our advertised speed * capabilities. */ EFSYS_ASSERT(0); } fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_phy_lp_cap_get( __in efx_nic_t *enp, __out uint32_t *maskp) { efx_port_t *epp = &(enp->en_port); EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); *maskp = epp->ep_lp_cap_mask; } __checkReturn efx_rc_t efx_phy_oui_get( __in efx_nic_t *enp, __out uint32_t *ouip) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); return (epop->epo_oui_get(enp, ouip)); } void efx_phy_media_type_get( __in efx_nic_t *enp, __out efx_phy_media_type_t *typep) { efx_port_t *epp = &(enp->en_port); EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); if (epp->ep_module_type != EFX_PHY_MEDIA_INVALID) *typep = epp->ep_module_type; else *typep = epp->ep_fixed_port_type; } __checkReturn efx_rc_t efx_phy_module_get_info( __in efx_nic_t *enp, __in uint8_t dev_addr, __in uint8_t offset, __in uint8_t len, __out_bcount(len) uint8_t *data) { efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT(data != NULL); if ((uint32_t)offset + len > 0xff) { rc = EINVAL; goto fail1; } if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr, offset, len, data)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_PHY_STATS #if EFSYS_OPT_NAMES /* START MKCONFIG GENERATED PhyStatNamesBlock d5f79b4bc2c050fe */ static const char *__efx_phy_stat_name[] = { "oui", "pma_pmd_link_up", "pma_pmd_rx_fault", "pma_pmd_tx_fault", "pma_pmd_rev_a", "pma_pmd_rev_b", "pma_pmd_rev_c", "pma_pmd_rev_d", "pcs_link_up", "pcs_rx_fault", "pcs_tx_fault", "pcs_ber", "pcs_block_errors", "phy_xs_link_up", "phy_xs_rx_fault", "phy_xs_tx_fault", "phy_xs_align", "phy_xs_sync_a", "phy_xs_sync_b", "phy_xs_sync_c", "phy_xs_sync_d", "an_link_up", "an_master", "an_local_rx_ok", "an_remote_rx_ok", "cl22ext_link_up", "snr_a", "snr_b", "snr_c", "snr_d", "pma_pmd_signal_a", "pma_pmd_signal_b", "pma_pmd_signal_c", "pma_pmd_signal_d", "an_complete", "pma_pmd_rev_major", "pma_pmd_rev_minor", "pma_pmd_rev_micro", "pcs_fw_version_0", "pcs_fw_version_1", "pcs_fw_version_2", "pcs_fw_version_3", "pcs_fw_build_yy", "pcs_fw_build_mm", "pcs_fw_build_dd", "pcs_op_mode", }; /* END MKCONFIG GENERATED PhyStatNamesBlock */ const char * efx_phy_stat_name( __in efx_nic_t *enp, __in efx_phy_stat_t type) { _NOTE(ARGUNUSED(enp)) EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(type, <, EFX_PHY_NSTATS); return (__efx_phy_stat_name[type]); } #endif /* EFSYS_OPT_NAMES */ __checkReturn efx_rc_t efx_phy_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); return (epop->epo_stats_update(enp, esmp, stat)); } #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_PHY_PROPS #if EFSYS_OPT_NAMES const char * efx_phy_prop_name( __in efx_nic_t *enp, __in unsigned int id) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); return (epop->epo_prop_name(enp, id)); } #endif /* EFSYS_OPT_NAMES */ __checkReturn efx_rc_t efx_phy_prop_get( __in efx_nic_t *enp, __in unsigned int id, __in uint32_t flags, __out uint32_t *valp) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); return (epop->epo_prop_get(enp, id, flags, valp)); } __checkReturn efx_rc_t efx_phy_prop_set( __in efx_nic_t *enp, __in unsigned int id, __in uint32_t val) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); return (epop->epo_prop_set(enp, id, val)); } #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_BIST __checkReturn efx_rc_t efx_bist_enable_offline( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); if (epop->epo_bist_enable_offline == NULL) { rc = ENOTSUP; goto fail1; } if ((rc = epop->epo_bist_enable_offline(enp)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_bist_start( __in efx_nic_t *enp, __in efx_bist_type_t type) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN); if (epop->epo_bist_start == NULL) { rc = ENOTSUP; goto fail1; } if ((rc = epop->epo_bist_start(enp, type)) != 0) goto fail2; epp->ep_current_bist = type; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_bist_poll( __in efx_nic_t *enp, __in efx_bist_type_t type, __out efx_bist_result_t *resultp, __out_opt uint32_t *value_maskp, __out_ecount_opt(count) unsigned long *valuesp, __in size_t count) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); EFSYS_ASSERT3U(epp->ep_current_bist, ==, type); EFSYS_ASSERT(epop->epo_bist_poll != NULL); if (epop->epo_bist_poll == NULL) { rc = ENOTSUP; goto fail1; } if ((rc = epop->epo_bist_poll(enp, type, resultp, value_maskp, valuesp, count)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_bist_stop( __in efx_nic_t *enp, __in efx_bist_type_t type) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); EFSYS_ASSERT3U(epp->ep_current_bist, ==, type); EFSYS_ASSERT(epop->epo_bist_stop != NULL); if (epop->epo_bist_stop != NULL) epop->epo_bist_stop(enp, type); epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN; } #endif /* EFSYS_OPT_BIST */ void efx_phy_unprobe( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); epp->ep_epop = NULL; epp->ep_adv_cap_mask = 0; epp->ep_port = 0; epp->ep_phy_type = 0; } Index: head/sys/dev/sfxge/common/efx_port.c =================================================================== --- head/sys/dev/sfxge/common/efx_port.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_port.c (revision 299517) @@ -1,255 +1,255 @@ /*- * Copyright (c) 2009-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" __checkReturn efx_rc_t efx_port_init( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); if (enp->en_mod_flags & EFX_MOD_PORT) { rc = EINVAL; goto fail1; } enp->en_mod_flags |= EFX_MOD_PORT; epp->ep_mac_type = EFX_MAC_INVALID; epp->ep_link_mode = EFX_LINK_UNKNOWN; epp->ep_mac_drain = B_TRUE; /* Configure the MAC */ if ((rc = efx_mac_select(enp)) != 0) goto fail1; epp->ep_emop->emo_reconfigure(enp); /* Pick up current phy capababilities */ efx_port_poll(enp, NULL); /* * Turn on the PHY if available, otherwise reset it, and * reconfigure it with the current configuration. */ if (epop->epo_power != NULL) { if ((rc = epop->epo_power(enp, B_TRUE)) != 0) goto fail2; } else { if ((rc = epop->epo_reset(enp)) != 0) goto fail2; } EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY); enp->en_reset_flags &= ~EFX_RESET_PHY; if ((rc = epop->epo_reconfigure(enp)) != 0) goto fail3; return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); enp->en_mod_flags &= ~EFX_MOD_PORT; return (rc); } __checkReturn efx_rc_t efx_port_poll( __in efx_nic_t *enp, __out_opt efx_link_mode_t *link_modep) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_link_mode_t ignore_link_mode; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); EFSYS_ASSERT(emop != NULL); EFSYS_ASSERT(!epp->ep_mac_stats_pending); if (link_modep == NULL) link_modep = &ignore_link_mode; if ((rc = emop->emo_poll(enp, link_modep)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_LOOPBACK __checkReturn efx_rc_t efx_port_loopback_set( __in efx_nic_t *enp, __in efx_link_mode_t link_mode, __in efx_loopback_type_t loopback_type) { efx_port_t *epp = &(enp->en_port); efx_nic_cfg_t *encp = &(enp->en_nic_cfg); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); EFSYS_ASSERT(emop != NULL); EFSYS_ASSERT(link_mode < EFX_LINK_NMODES); if (EFX_TEST_QWORD_BIT(encp->enc_loopback_types[link_mode], loopback_type) == 0) { rc = ENOTSUP; goto fail1; } if (epp->ep_loopback_type == loopback_type && epp->ep_loopback_link_mode == link_mode) return (0); if ((rc = emop->emo_loopback_set(enp, link_mode, loopback_type)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_NAMES static const char *__efx_loopback_type_name[] = { "OFF", "DATA", "GMAC", "XGMII", "XGXS", "XAUI", "GMII", "SGMII", "XGBR", "XFI", "XAUI_FAR", "GMII_FAR", "SGMII_FAR", "XFI_FAR", "GPHY", "PHY_XS", "PCS", "PMA_PMD", "XPORT", "XGMII_WS", "XAUI_WS", "XAUI_WS_FAR", "XAUI_WS_NEAR", "GMII_WS", "XFI_WS", "XFI_WS_FAR", "PHYXS_WS", "PMA_INT", "SD_NEAR", "SD_FAR", "PMA_INT_WS", "SD_FEP2_WS", "SD_FEP1_5_WS", "SD_FEP_WS", "SD_FES_WS", }; __checkReturn const char * efx_loopback_type_name( __in efx_nic_t *enp, __in efx_loopback_type_t type) { EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__efx_loopback_type_name) == EFX_LOOPBACK_NTYPES); _NOTE(ARGUNUSED(enp)) EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(type, <, EFX_LOOPBACK_NTYPES); return (__efx_loopback_type_name[type]); } #endif /* EFSYS_OPT_NAMES */ #endif /* EFSYS_OPT_LOOPBACK */ void efx_port_fini( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); EFSYS_ASSERT(epp->ep_mac_drain); epp->ep_emop = NULL; epp->ep_mac_type = EFX_MAC_INVALID; epp->ep_mac_drain = B_FALSE; /* Turn off the PHY */ if (epop->epo_power != NULL) (void) epop->epo_power(enp, B_FALSE); enp->en_mod_flags &= ~EFX_MOD_PORT; } Index: head/sys/dev/sfxge/common/efx_rx.c =================================================================== --- head/sys/dev/sfxge/common/efx_rx.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_rx.c (revision 299517) @@ -1,1222 +1,1222 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_rx_init( __in efx_nic_t *enp); static void falconsiena_rx_fini( __in efx_nic_t *enp); #if EFSYS_OPT_RX_SCATTER static __checkReturn efx_rc_t falconsiena_rx_scatter_enable( __in efx_nic_t *enp, __in unsigned int buf_size); #endif /* EFSYS_OPT_RX_SCATTER */ #if EFSYS_OPT_RX_SCALE static __checkReturn efx_rc_t falconsiena_rx_scale_mode_set( __in efx_nic_t *enp, __in efx_rx_hash_alg_t alg, __in efx_rx_hash_type_t type, __in boolean_t insert); static __checkReturn efx_rc_t falconsiena_rx_scale_key_set( __in efx_nic_t *enp, __in_ecount(n) uint8_t *key, __in size_t n); static __checkReturn efx_rc_t falconsiena_rx_scale_tbl_set( __in efx_nic_t *enp, __in_ecount(n) unsigned int *table, __in size_t n); static __checkReturn uint32_t falconsiena_rx_prefix_hash( __in efx_nic_t *enp, __in efx_rx_hash_alg_t func, __in uint8_t *buffer); #endif /* EFSYS_OPT_RX_SCALE */ static __checkReturn efx_rc_t falconsiena_rx_prefix_pktlen( __in efx_nic_t *enp, __in uint8_t *buffer, __out uint16_t *lengthp); static void falconsiena_rx_qpost( __in efx_rxq_t *erp, __in_ecount(n) efsys_dma_addr_t *addrp, __in size_t size, __in unsigned int n, __in unsigned int completed, __in unsigned int added); static void falconsiena_rx_qpush( __in efx_rxq_t *erp, __in unsigned int added, __inout unsigned int *pushedp); static __checkReturn efx_rc_t falconsiena_rx_qflush( __in efx_rxq_t *erp); static void falconsiena_rx_qenable( __in efx_rxq_t *erp); static __checkReturn efx_rc_t falconsiena_rx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efx_rxq_type_t type, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in efx_evq_t *eep, __in efx_rxq_t *erp); static void falconsiena_rx_qdestroy( __in efx_rxq_t *erp); #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_SIENA -static efx_rx_ops_t __efx_rx_siena_ops = { +static const efx_rx_ops_t __efx_rx_siena_ops = { falconsiena_rx_init, /* erxo_init */ falconsiena_rx_fini, /* erxo_fini */ #if EFSYS_OPT_RX_SCATTER falconsiena_rx_scatter_enable, /* erxo_scatter_enable */ #endif #if EFSYS_OPT_RX_SCALE falconsiena_rx_scale_mode_set, /* erxo_scale_mode_set */ falconsiena_rx_scale_key_set, /* erxo_scale_key_set */ falconsiena_rx_scale_tbl_set, /* erxo_scale_tbl_set */ falconsiena_rx_prefix_hash, /* erxo_prefix_hash */ #endif falconsiena_rx_prefix_pktlen, /* erxo_prefix_pktlen */ falconsiena_rx_qpost, /* erxo_qpost */ falconsiena_rx_qpush, /* erxo_qpush */ falconsiena_rx_qflush, /* erxo_qflush */ falconsiena_rx_qenable, /* erxo_qenable */ falconsiena_rx_qcreate, /* erxo_qcreate */ falconsiena_rx_qdestroy, /* erxo_qdestroy */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_rx_ops_t __efx_rx_ef10_ops = { +static const efx_rx_ops_t __efx_rx_ef10_ops = { ef10_rx_init, /* erxo_init */ ef10_rx_fini, /* erxo_fini */ #if EFSYS_OPT_RX_SCATTER ef10_rx_scatter_enable, /* erxo_scatter_enable */ #endif #if EFSYS_OPT_RX_SCALE ef10_rx_scale_mode_set, /* erxo_scale_mode_set */ ef10_rx_scale_key_set, /* erxo_scale_key_set */ ef10_rx_scale_tbl_set, /* erxo_scale_tbl_set */ ef10_rx_prefix_hash, /* erxo_prefix_hash */ #endif ef10_rx_prefix_pktlen, /* erxo_prefix_pktlen */ ef10_rx_qpost, /* erxo_qpost */ ef10_rx_qpush, /* erxo_qpush */ ef10_rx_qflush, /* erxo_qflush */ ef10_rx_qenable, /* erxo_qenable */ ef10_rx_qcreate, /* erxo_qcreate */ ef10_rx_qdestroy, /* erxo_qdestroy */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_rx_init( __inout efx_nic_t *enp) { - efx_rx_ops_t *erxop; + const efx_rx_ops_t *erxop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); if (!(enp->en_mod_flags & EFX_MOD_EV)) { rc = EINVAL; goto fail1; } if (enp->en_mod_flags & EFX_MOD_RX) { rc = EINVAL; goto fail2; } switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - erxop = (efx_rx_ops_t *)&__efx_rx_siena_ops; + erxop = &__efx_rx_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - erxop = (efx_rx_ops_t *)&__efx_rx_ef10_ops; + erxop = &__efx_rx_ef10_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - erxop = (efx_rx_ops_t *)&__efx_rx_ef10_ops; + erxop = &__efx_rx_ef10_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail3; } if ((rc = erxop->erxo_init(enp)) != 0) goto fail4; enp->en_erxop = erxop; enp->en_mod_flags |= EFX_MOD_RX; return (0); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); enp->en_erxop = NULL; enp->en_mod_flags &= ~EFX_MOD_RX; return (rc); } void efx_rx_fini( __in efx_nic_t *enp) { - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); EFSYS_ASSERT3U(enp->en_rx_qcount, ==, 0); erxop->erxo_fini(enp); enp->en_erxop = NULL; enp->en_mod_flags &= ~EFX_MOD_RX; } #if EFSYS_OPT_RX_SCATTER __checkReturn efx_rc_t efx_rx_scatter_enable( __in efx_nic_t *enp, __in unsigned int buf_size) { - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); if ((rc = erxop->erxo_scatter_enable(enp, buf_size)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_RX_SCATTER */ #if EFSYS_OPT_RX_SCALE __checkReturn efx_rc_t efx_rx_hash_support_get( __in efx_nic_t *enp, __out efx_rx_hash_support_t *supportp) { efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); if (supportp == NULL) { rc = EINVAL; goto fail1; } /* Report if resources are available to insert RX hash value */ *supportp = enp->en_hash_support; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_rx_scale_support_get( __in efx_nic_t *enp, __out efx_rx_scale_support_t *supportp) { efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); if (supportp == NULL) { rc = EINVAL; goto fail1; } /* Report if resources are available to support RSS */ *supportp = enp->en_rss_support; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_rx_scale_mode_set( __in efx_nic_t *enp, __in efx_rx_hash_alg_t alg, __in efx_rx_hash_type_t type, __in boolean_t insert) { - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); if (erxop->erxo_scale_mode_set != NULL) { if ((rc = erxop->erxo_scale_mode_set(enp, alg, type, insert)) != 0) goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_RX_SCALE */ #if EFSYS_OPT_RX_SCALE __checkReturn efx_rc_t efx_rx_scale_key_set( __in efx_nic_t *enp, __in_ecount(n) uint8_t *key, __in size_t n) { - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); if ((rc = erxop->erxo_scale_key_set(enp, key, n)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_RX_SCALE */ #if EFSYS_OPT_RX_SCALE __checkReturn efx_rc_t efx_rx_scale_tbl_set( __in efx_nic_t *enp, __in_ecount(n) unsigned int *table, __in size_t n) { - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); if ((rc = erxop->erxo_scale_tbl_set(enp, table, n)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_RX_SCALE */ void efx_rx_qpost( __in efx_rxq_t *erp, __in_ecount(n) efsys_dma_addr_t *addrp, __in size_t size, __in unsigned int n, __in unsigned int completed, __in unsigned int added) { efx_nic_t *enp = erp->er_enp; - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC); erxop->erxo_qpost(erp, addrp, size, n, completed, added); } void efx_rx_qpush( __in efx_rxq_t *erp, __in unsigned int added, __inout unsigned int *pushedp) { efx_nic_t *enp = erp->er_enp; - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC); erxop->erxo_qpush(erp, added, pushedp); } __checkReturn efx_rc_t efx_rx_qflush( __in efx_rxq_t *erp) { efx_nic_t *enp = erp->er_enp; - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; efx_rc_t rc; EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC); if ((rc = erxop->erxo_qflush(erp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_rx_qenable( __in efx_rxq_t *erp) { efx_nic_t *enp = erp->er_enp; - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC); erxop->erxo_qenable(erp); } __checkReturn efx_rc_t efx_rx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efx_rxq_type_t type, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in efx_evq_t *eep, __deref_out efx_rxq_t **erpp) { - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; efx_rxq_t *erp; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_RX); /* Allocate an RXQ object */ EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_rxq_t), erp); if (erp == NULL) { rc = ENOMEM; goto fail1; } erp->er_magic = EFX_RXQ_MAGIC; erp->er_enp = enp; erp->er_index = index; erp->er_mask = n - 1; erp->er_esmp = esmp; if ((rc = erxop->erxo_qcreate(enp, index, label, type, esmp, n, id, eep, erp)) != 0) goto fail2; enp->en_rx_qcount++; *erpp = erp; return (0); fail2: EFSYS_PROBE(fail2); EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_rx_qdestroy( __in efx_rxq_t *erp) { efx_nic_t *enp = erp->er_enp; - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC); erxop->erxo_qdestroy(erp); } __checkReturn efx_rc_t efx_psuedo_hdr_pkt_length_get( __in efx_nic_t *enp, __in uint8_t *buffer, __out uint16_t *lengthp) { - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; return (erxop->erxo_prefix_pktlen(enp, buffer, lengthp)); } #if EFSYS_OPT_RX_SCALE __checkReturn uint32_t efx_psuedo_hdr_hash_get( __in efx_nic_t *enp, __in efx_rx_hash_alg_t func, __in uint8_t *buffer) { - efx_rx_ops_t *erxop = enp->en_erxop; + const efx_rx_ops_t *erxop = enp->en_erxop; EFSYS_ASSERT3U(enp->en_hash_support, ==, EFX_RX_HASH_AVAILABLE); return (erxop->erxo_prefix_hash(enp, func, buffer)); } #endif /* EFSYS_OPT_RX_SCALE */ #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_rx_init( __in efx_nic_t *enp) { efx_oword_t oword; unsigned int index; EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_DESC_PUSH_EN, 0); EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 0); EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH, 0); EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP, 0); EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR, 0); EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_USR_BUF_SIZE, 0x3000 / 32); EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword); /* Zero the RSS table */ for (index = 0; index < FR_BZ_RX_INDIRECTION_TBL_ROWS; index++) { EFX_ZERO_OWORD(oword); EFX_BAR_TBL_WRITEO(enp, FR_BZ_RX_INDIRECTION_TBL, index, &oword, B_TRUE); } #if EFSYS_OPT_RX_SCALE /* The RSS key and indirection table are writable. */ enp->en_rss_support = EFX_RX_SCALE_EXCLUSIVE; /* Hardware can insert RX hash with/without RSS */ enp->en_hash_support = EFX_RX_HASH_AVAILABLE; #endif /* EFSYS_OPT_RX_SCALE */ return (0); } #if EFSYS_OPT_RX_SCATTER static __checkReturn efx_rc_t falconsiena_rx_scatter_enable( __in efx_nic_t *enp, __in unsigned int buf_size) { unsigned int nbuf32; efx_oword_t oword; efx_rc_t rc; nbuf32 = buf_size / 32; if ((nbuf32 == 0) || (nbuf32 >= (1 << FRF_BZ_RX_USR_BUF_SIZE_WIDTH)) || ((buf_size % 32) != 0)) { rc = EINVAL; goto fail1; } if (enp->en_rx_qcount > 0) { rc = EBUSY; goto fail2; } /* Set scatter buffer size */ EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_USR_BUF_SIZE, nbuf32); EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword); /* Enable scatter for packets not matching a filter */ EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_BZ_SCATTER_ENBL_NO_MATCH_Q, 1); EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_RX_SCATTER */ #define EFX_RX_LFSR_HASH(_enp, _insert) \ do { \ efx_oword_t oword; \ \ EFX_BAR_READO((_enp), FR_AZ_RX_CFG_REG, &oword); \ EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 0); \ EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH, 0); \ EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP, 0); \ EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR, \ (_insert) ? 1 : 0); \ EFX_BAR_WRITEO((_enp), FR_AZ_RX_CFG_REG, &oword); \ \ if ((_enp)->en_family == EFX_FAMILY_SIENA) { \ EFX_BAR_READO((_enp), FR_CZ_RX_RSS_IPV6_REG3, \ &oword); \ EFX_SET_OWORD_FIELD(oword, \ FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 0); \ EFX_BAR_WRITEO((_enp), FR_CZ_RX_RSS_IPV6_REG3, \ &oword); \ } \ \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_RX_TOEPLITZ_IPV4_HASH(_enp, _insert, _ip, _tcp) \ do { \ efx_oword_t oword; \ \ EFX_BAR_READO((_enp), FR_AZ_RX_CFG_REG, &oword); \ EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_ALG, 1); \ EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_IP_HASH, \ (_ip) ? 1 : 0); \ EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_TCP_SUP, \ (_tcp) ? 0 : 1); \ EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_HASH_INSRT_HDR, \ (_insert) ? 1 : 0); \ EFX_BAR_WRITEO((_enp), FR_AZ_RX_CFG_REG, &oword); \ \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #define EFX_RX_TOEPLITZ_IPV6_HASH(_enp, _ip, _tcp, _rc) \ do { \ efx_oword_t oword; \ \ EFX_BAR_READO((_enp), FR_CZ_RX_RSS_IPV6_REG3, &oword); \ EFX_SET_OWORD_FIELD(oword, \ FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1); \ EFX_SET_OWORD_FIELD(oword, \ FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, (_ip) ? 1 : 0); \ EFX_SET_OWORD_FIELD(oword, \ FRF_CZ_RX_RSS_IPV6_TCP_SUPPRESS, (_tcp) ? 0 : 1); \ EFX_BAR_WRITEO((_enp), FR_CZ_RX_RSS_IPV6_REG3, &oword); \ \ (_rc) = 0; \ \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #if EFSYS_OPT_RX_SCALE static __checkReturn efx_rc_t falconsiena_rx_scale_mode_set( __in efx_nic_t *enp, __in efx_rx_hash_alg_t alg, __in efx_rx_hash_type_t type, __in boolean_t insert) { efx_rc_t rc; switch (alg) { case EFX_RX_HASHALG_LFSR: EFX_RX_LFSR_HASH(enp, insert); break; case EFX_RX_HASHALG_TOEPLITZ: EFX_RX_TOEPLITZ_IPV4_HASH(enp, insert, type & (1 << EFX_RX_HASH_IPV4), type & (1 << EFX_RX_HASH_TCPIPV4)); EFX_RX_TOEPLITZ_IPV6_HASH(enp, type & (1 << EFX_RX_HASH_IPV6), type & (1 << EFX_RX_HASH_TCPIPV6), rc); if (rc != 0) goto fail1; break; default: rc = EINVAL; goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); EFX_RX_LFSR_HASH(enp, B_FALSE); return (rc); } #endif #if EFSYS_OPT_RX_SCALE static __checkReturn efx_rc_t falconsiena_rx_scale_key_set( __in efx_nic_t *enp, __in_ecount(n) uint8_t *key, __in size_t n) { efx_oword_t oword; unsigned int byte; unsigned int offset; efx_rc_t rc; byte = 0; /* Write Toeplitz IPv4 hash key */ EFX_ZERO_OWORD(oword); for (offset = (FRF_BZ_RX_RSS_TKEY_LBN + FRF_BZ_RX_RSS_TKEY_WIDTH) / 8; offset > 0 && byte < n; --offset) oword.eo_u8[offset - 1] = key[byte++]; EFX_BAR_WRITEO(enp, FR_BZ_RX_RSS_TKEY_REG, &oword); byte = 0; /* Verify Toeplitz IPv4 hash key */ EFX_BAR_READO(enp, FR_BZ_RX_RSS_TKEY_REG, &oword); for (offset = (FRF_BZ_RX_RSS_TKEY_LBN + FRF_BZ_RX_RSS_TKEY_WIDTH) / 8; offset > 0 && byte < n; --offset) { if (oword.eo_u8[offset - 1] != key[byte++]) { rc = EFAULT; goto fail1; } } if ((enp->en_features & EFX_FEATURE_IPV6) == 0) goto done; byte = 0; /* Write Toeplitz IPv6 hash key 3 */ EFX_BAR_READO(enp, FR_CZ_RX_RSS_IPV6_REG3, &oword); for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH) / 8; offset > 0 && byte < n; --offset) oword.eo_u8[offset - 1] = key[byte++]; EFX_BAR_WRITEO(enp, FR_CZ_RX_RSS_IPV6_REG3, &oword); /* Write Toeplitz IPv6 hash key 2 */ EFX_ZERO_OWORD(oword); for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN + FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH) / 8; offset > 0 && byte < n; --offset) oword.eo_u8[offset - 1] = key[byte++]; EFX_BAR_WRITEO(enp, FR_CZ_RX_RSS_IPV6_REG2, &oword); /* Write Toeplitz IPv6 hash key 1 */ EFX_ZERO_OWORD(oword); for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN + FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH) / 8; offset > 0 && byte < n; --offset) oword.eo_u8[offset - 1] = key[byte++]; EFX_BAR_WRITEO(enp, FR_CZ_RX_RSS_IPV6_REG1, &oword); byte = 0; /* Verify Toeplitz IPv6 hash key 3 */ EFX_BAR_READO(enp, FR_CZ_RX_RSS_IPV6_REG3, &oword); for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH) / 8; offset > 0 && byte < n; --offset) { if (oword.eo_u8[offset - 1] != key[byte++]) { rc = EFAULT; goto fail2; } } /* Verify Toeplitz IPv6 hash key 2 */ EFX_BAR_READO(enp, FR_CZ_RX_RSS_IPV6_REG2, &oword); for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_MID_LBN + FRF_CZ_RX_RSS_IPV6_TKEY_MID_WIDTH) / 8; offset > 0 && byte < n; --offset) { if (oword.eo_u8[offset - 1] != key[byte++]) { rc = EFAULT; goto fail3; } } /* Verify Toeplitz IPv6 hash key 1 */ EFX_BAR_READO(enp, FR_CZ_RX_RSS_IPV6_REG1, &oword); for (offset = (FRF_CZ_RX_RSS_IPV6_TKEY_LO_LBN + FRF_CZ_RX_RSS_IPV6_TKEY_LO_WIDTH) / 8; offset > 0 && byte < n; --offset) { if (oword.eo_u8[offset - 1] != key[byte++]) { rc = EFAULT; goto fail4; } } done: return (0); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif #if EFSYS_OPT_RX_SCALE static __checkReturn efx_rc_t falconsiena_rx_scale_tbl_set( __in efx_nic_t *enp, __in_ecount(n) unsigned int *table, __in size_t n) { efx_oword_t oword; int index; efx_rc_t rc; EFX_STATIC_ASSERT(EFX_RSS_TBL_SIZE == FR_BZ_RX_INDIRECTION_TBL_ROWS); EFX_STATIC_ASSERT(EFX_MAXRSS == (1 << FRF_BZ_IT_QUEUE_WIDTH)); if (n > FR_BZ_RX_INDIRECTION_TBL_ROWS) { rc = EINVAL; goto fail1; } for (index = 0; index < FR_BZ_RX_INDIRECTION_TBL_ROWS; index++) { uint32_t byte; /* Calculate the entry to place in the table */ byte = (n > 0) ? (uint32_t)table[index % n] : 0; EFSYS_PROBE2(table, int, index, uint32_t, byte); EFX_POPULATE_OWORD_1(oword, FRF_BZ_IT_QUEUE, byte); /* Write the table */ EFX_BAR_TBL_WRITEO(enp, FR_BZ_RX_INDIRECTION_TBL, index, &oword, B_TRUE); } for (index = FR_BZ_RX_INDIRECTION_TBL_ROWS - 1; index >= 0; --index) { uint32_t byte; /* Determine if we're starting a new batch */ byte = (n > 0) ? (uint32_t)table[index % n] : 0; /* Read the table */ EFX_BAR_TBL_READO(enp, FR_BZ_RX_INDIRECTION_TBL, index, &oword, B_TRUE); /* Verify the entry */ if (EFX_OWORD_FIELD(oword, FRF_BZ_IT_QUEUE) != byte) { rc = EFAULT; goto fail2; } } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* * Falcon/Siena psuedo-header * -------------------------- * * Receive packets are prefixed by an optional 16 byte pseudo-header. * The psuedo-header is a byte array of one of the forms: * * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 * xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.TT.TT.TT.TT * xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.xx.LL.LL * * where: * TT.TT.TT.TT Toeplitz hash (32-bit big-endian) * LL.LL LFSR hash (16-bit big-endian) */ #if EFSYS_OPT_RX_SCALE static __checkReturn uint32_t falconsiena_rx_prefix_hash( __in efx_nic_t *enp, __in efx_rx_hash_alg_t func, __in uint8_t *buffer) { switch (func) { case EFX_RX_HASHALG_TOEPLITZ: return ((buffer[12] << 24) | (buffer[13] << 16) | (buffer[14] << 8) | buffer[15]); case EFX_RX_HASHALG_LFSR: return ((buffer[14] << 8) | buffer[15]); default: EFSYS_ASSERT(0); return (0); } } #endif /* EFSYS_OPT_RX_SCALE */ static __checkReturn efx_rc_t falconsiena_rx_prefix_pktlen( __in efx_nic_t *enp, __in uint8_t *buffer, __out uint16_t *lengthp) { /* Not supported by Falcon/Siena hardware */ EFSYS_ASSERT(0); return (ENOTSUP); } static void falconsiena_rx_qpost( __in efx_rxq_t *erp, __in_ecount(n) efsys_dma_addr_t *addrp, __in size_t size, __in unsigned int n, __in unsigned int completed, __in unsigned int added) { efx_qword_t qword; unsigned int i; unsigned int offset; unsigned int id; /* The client driver must not overfill the queue */ EFSYS_ASSERT3U(added - completed + n, <=, EFX_RXQ_LIMIT(erp->er_mask + 1)); id = added & (erp->er_mask); for (i = 0; i < n; i++) { EFSYS_PROBE4(rx_post, unsigned int, erp->er_index, unsigned int, id, efsys_dma_addr_t, addrp[i], size_t, size); EFX_POPULATE_QWORD_3(qword, FSF_AZ_RX_KER_BUF_SIZE, (uint32_t)(size), FSF_AZ_RX_KER_BUF_ADDR_DW0, (uint32_t)(addrp[i] & 0xffffffff), FSF_AZ_RX_KER_BUF_ADDR_DW1, (uint32_t)(addrp[i] >> 32)); offset = id * sizeof (efx_qword_t); EFSYS_MEM_WRITEQ(erp->er_esmp, offset, &qword); id = (id + 1) & (erp->er_mask); } } static void falconsiena_rx_qpush( __in efx_rxq_t *erp, __in unsigned int added, __inout unsigned int *pushedp) { efx_nic_t *enp = erp->er_enp; unsigned int pushed = *pushedp; uint32_t wptr; efx_oword_t oword; efx_dword_t dword; /* All descriptors are pushed */ *pushedp = added; /* Push the populated descriptors out */ wptr = added & erp->er_mask; EFX_POPULATE_OWORD_1(oword, FRF_AZ_RX_DESC_WPTR, wptr); /* Only write the third DWORD */ EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3)); /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */ EFX_DMA_SYNC_QUEUE_FOR_DEVICE(erp->er_esmp, erp->er_mask + 1, wptr, pushed & erp->er_mask); EFSYS_PIO_WRITE_BARRIER(); EFX_BAR_TBL_WRITED3(enp, FR_BZ_RX_DESC_UPD_REGP0, erp->er_index, &dword, B_FALSE); } static __checkReturn efx_rc_t falconsiena_rx_qflush( __in efx_rxq_t *erp) { efx_nic_t *enp = erp->er_enp; efx_oword_t oword; uint32_t label; label = erp->er_index; /* Flush the queue */ EFX_POPULATE_OWORD_2(oword, FRF_AZ_RX_FLUSH_DESCQ_CMD, 1, FRF_AZ_RX_FLUSH_DESCQ, label); EFX_BAR_WRITEO(enp, FR_AZ_RX_FLUSH_DESCQ_REG, &oword); return (0); } static void falconsiena_rx_qenable( __in efx_rxq_t *erp) { efx_nic_t *enp = erp->er_enp; efx_oword_t oword; EFSYS_ASSERT3U(erp->er_magic, ==, EFX_RXQ_MAGIC); EFX_BAR_TBL_READO(enp, FR_AZ_RX_DESC_PTR_TBL, erp->er_index, &oword, B_TRUE); EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DC_HW_RPTR, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DESCQ_HW_RPTR, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_DESCQ_EN, 1); EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL, erp->er_index, &oword, B_TRUE); } static __checkReturn efx_rc_t falconsiena_rx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efx_rxq_type_t type, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in efx_evq_t *eep, __in efx_rxq_t *erp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_oword_t oword; uint32_t size; boolean_t jumbo; efx_rc_t rc; EFX_STATIC_ASSERT(EFX_EV_RX_NLABELS == (1 << FRF_AZ_RX_DESCQ_LABEL_WIDTH)); EFSYS_ASSERT3U(label, <, EFX_EV_RX_NLABELS); EFSYS_ASSERT3U(enp->en_rx_qcount + 1, <, encp->enc_rxq_limit); EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MAXNDESCS)); EFX_STATIC_ASSERT(ISP2(EFX_RXQ_MINNDESCS)); if (!ISP2(n) || (n < EFX_RXQ_MINNDESCS) || (n > EFX_RXQ_MAXNDESCS)) { rc = EINVAL; goto fail1; } if (index >= encp->enc_rxq_limit) { rc = EINVAL; goto fail2; } for (size = 0; (1 << size) <= (EFX_RXQ_MAXNDESCS / EFX_RXQ_MINNDESCS); size++) if ((1 << size) == (int)(n / EFX_RXQ_MINNDESCS)) break; if (id + (1 << size) >= encp->enc_buftbl_limit) { rc = EINVAL; goto fail3; } switch (type) { case EFX_RXQ_TYPE_DEFAULT: jumbo = B_FALSE; break; #if EFSYS_OPT_RX_SCATTER case EFX_RXQ_TYPE_SCATTER: if (enp->en_family < EFX_FAMILY_SIENA) { rc = EINVAL; goto fail4; } jumbo = B_TRUE; break; #endif /* EFSYS_OPT_RX_SCATTER */ default: rc = EINVAL; goto fail4; } /* Set up the new descriptor queue */ EFX_POPULATE_OWORD_7(oword, FRF_AZ_RX_DESCQ_BUF_BASE_ID, id, FRF_AZ_RX_DESCQ_EVQ_ID, eep->ee_index, FRF_AZ_RX_DESCQ_OWNER_ID, 0, FRF_AZ_RX_DESCQ_LABEL, label, FRF_AZ_RX_DESCQ_SIZE, size, FRF_AZ_RX_DESCQ_TYPE, 0, FRF_AZ_RX_DESCQ_JUMBO, jumbo); EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL, erp->er_index, &oword, B_TRUE); 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 void falconsiena_rx_qdestroy( __in efx_rxq_t *erp) { efx_nic_t *enp = erp->er_enp; efx_oword_t oword; EFSYS_ASSERT(enp->en_rx_qcount != 0); --enp->en_rx_qcount; /* Purge descriptor queue */ EFX_ZERO_OWORD(oword); EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_DESC_PTR_TBL, erp->er_index, &oword, B_TRUE); /* Free the RXQ object */ EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_rxq_t), erp); } static void falconsiena_rx_fini( __in efx_nic_t *enp) { _NOTE(ARGUNUSED(enp)) } #endif /* EFSYS_OPT_SIENA */ Index: head/sys/dev/sfxge/common/efx_tx.c =================================================================== --- head/sys/dev/sfxge/common/efx_tx.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_tx.c (revision 299517) @@ -1,1091 +1,1091 @@ /*- * Copyright (c) 2007-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_QSTATS #define EFX_TX_QSTAT_INCR(_etp, _stat) \ do { \ (_etp)->et_stat[_stat]++; \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) #else #define EFX_TX_QSTAT_INCR(_etp, _stat) #endif #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_tx_init( __in efx_nic_t *enp); static void falconsiena_tx_fini( __in efx_nic_t *enp); static __checkReturn efx_rc_t falconsiena_tx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in uint16_t flags, __in efx_evq_t *eep, __in efx_txq_t *etp, __out unsigned int *addedp); static void falconsiena_tx_qdestroy( __in efx_txq_t *etp); static __checkReturn efx_rc_t falconsiena_tx_qpost( __in efx_txq_t *etp, __in_ecount(n) efx_buffer_t *eb, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp); static void falconsiena_tx_qpush( __in efx_txq_t *etp, __in unsigned int added, __in unsigned int pushed); static __checkReturn efx_rc_t falconsiena_tx_qpace( __in efx_txq_t *etp, __in unsigned int ns); static __checkReturn efx_rc_t falconsiena_tx_qflush( __in efx_txq_t *etp); static void falconsiena_tx_qenable( __in efx_txq_t *etp); __checkReturn efx_rc_t falconsiena_tx_qdesc_post( __in efx_txq_t *etp, __in_ecount(n) efx_desc_t *ed, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp); void falconsiena_tx_qdesc_dma_create( __in efx_txq_t *etp, __in efsys_dma_addr_t addr, __in size_t size, __in boolean_t eop, __out efx_desc_t *edp); #if EFSYS_OPT_QSTATS static void falconsiena_tx_qstats_update( __in efx_txq_t *etp, __inout_ecount(TX_NQSTATS) efsys_stat_t *stat); #endif #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_SIENA -static efx_tx_ops_t __efx_tx_siena_ops = { +static const efx_tx_ops_t __efx_tx_siena_ops = { falconsiena_tx_init, /* etxo_init */ falconsiena_tx_fini, /* etxo_fini */ falconsiena_tx_qcreate, /* etxo_qcreate */ falconsiena_tx_qdestroy, /* etxo_qdestroy */ falconsiena_tx_qpost, /* etxo_qpost */ falconsiena_tx_qpush, /* etxo_qpush */ falconsiena_tx_qpace, /* etxo_qpace */ falconsiena_tx_qflush, /* etxo_qflush */ falconsiena_tx_qenable, /* etxo_qenable */ NULL, /* etxo_qpio_enable */ NULL, /* etxo_qpio_disable */ NULL, /* etxo_qpio_write */ NULL, /* etxo_qpio_post */ falconsiena_tx_qdesc_post, /* etxo_qdesc_post */ falconsiena_tx_qdesc_dma_create, /* etxo_qdesc_dma_create */ NULL, /* etxo_qdesc_tso_create */ NULL, /* etxo_qdesc_tso2_create */ NULL, /* etxo_qdesc_vlantci_create */ #if EFSYS_OPT_QSTATS falconsiena_tx_qstats_update, /* etxo_qstats_update */ #endif }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON -static efx_tx_ops_t __efx_tx_hunt_ops = { +static const efx_tx_ops_t __efx_tx_hunt_ops = { ef10_tx_init, /* etxo_init */ ef10_tx_fini, /* etxo_fini */ ef10_tx_qcreate, /* etxo_qcreate */ ef10_tx_qdestroy, /* etxo_qdestroy */ ef10_tx_qpost, /* etxo_qpost */ ef10_tx_qpush, /* etxo_qpush */ ef10_tx_qpace, /* etxo_qpace */ ef10_tx_qflush, /* etxo_qflush */ ef10_tx_qenable, /* etxo_qenable */ ef10_tx_qpio_enable, /* etxo_qpio_enable */ ef10_tx_qpio_disable, /* etxo_qpio_disable */ ef10_tx_qpio_write, /* etxo_qpio_write */ ef10_tx_qpio_post, /* etxo_qpio_post */ ef10_tx_qdesc_post, /* etxo_qdesc_post */ ef10_tx_qdesc_dma_create, /* etxo_qdesc_dma_create */ hunt_tx_qdesc_tso_create, /* etxo_qdesc_tso_create */ ef10_tx_qdesc_tso2_create, /* etxo_qdesc_tso2_create */ ef10_tx_qdesc_vlantci_create, /* etxo_qdesc_vlantci_create */ #if EFSYS_OPT_QSTATS ef10_tx_qstats_update, /* etxo_qstats_update */ #endif }; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD -static efx_tx_ops_t __efx_tx_medford_ops = { +static const efx_tx_ops_t __efx_tx_medford_ops = { ef10_tx_init, /* etxo_init */ ef10_tx_fini, /* etxo_fini */ ef10_tx_qcreate, /* etxo_qcreate */ ef10_tx_qdestroy, /* etxo_qdestroy */ ef10_tx_qpost, /* etxo_qpost */ ef10_tx_qpush, /* etxo_qpush */ ef10_tx_qpace, /* etxo_qpace */ ef10_tx_qflush, /* etxo_qflush */ ef10_tx_qenable, /* etxo_qenable */ ef10_tx_qpio_enable, /* etxo_qpio_enable */ ef10_tx_qpio_disable, /* etxo_qpio_disable */ ef10_tx_qpio_write, /* etxo_qpio_write */ ef10_tx_qpio_post, /* etxo_qpio_post */ ef10_tx_qdesc_post, /* etxo_qdesc_post */ ef10_tx_qdesc_dma_create, /* etxo_qdesc_dma_create */ NULL, /* etxo_qdesc_tso_create */ ef10_tx_qdesc_tso2_create, /* etxo_qdesc_tso2_create */ ef10_tx_qdesc_vlantci_create, /* etxo_qdesc_vlantci_create */ #if EFSYS_OPT_QSTATS ef10_tx_qstats_update, /* etxo_qstats_update */ #endif }; #endif /* EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_tx_init( __in efx_nic_t *enp) { - efx_tx_ops_t *etxop; + const efx_tx_ops_t *etxop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); if (!(enp->en_mod_flags & EFX_MOD_EV)) { rc = EINVAL; goto fail1; } if (enp->en_mod_flags & EFX_MOD_TX) { rc = EINVAL; goto fail2; } switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - etxop = (efx_tx_ops_t *)&__efx_tx_siena_ops; + etxop = &__efx_tx_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - etxop = (efx_tx_ops_t *)&__efx_tx_hunt_ops; + etxop = &__efx_tx_hunt_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - etxop = (efx_tx_ops_t *)&__efx_tx_medford_ops; + etxop = &__efx_tx_medford_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail3; } EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0); if ((rc = etxop->etxo_init(enp)) != 0) goto fail4; enp->en_etxop = etxop; enp->en_mod_flags |= EFX_MOD_TX; return (0); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); enp->en_etxop = NULL; enp->en_mod_flags &= ~EFX_MOD_TX; return (rc); } void efx_tx_fini( __in efx_nic_t *enp) { - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX); EFSYS_ASSERT3U(enp->en_tx_qcount, ==, 0); etxop->etxo_fini(enp); enp->en_etxop = NULL; enp->en_mod_flags &= ~EFX_MOD_TX; } __checkReturn efx_rc_t efx_tx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in uint16_t flags, __in efx_evq_t *eep, __deref_out efx_txq_t **etpp, __out unsigned int *addedp) { - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_txq_t *etp; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TX); EFSYS_ASSERT3U(enp->en_tx_qcount + 1, <, encp->enc_txq_limit); /* Allocate an TXQ object */ EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_txq_t), etp); if (etp == NULL) { rc = ENOMEM; goto fail1; } etp->et_magic = EFX_TXQ_MAGIC; etp->et_enp = enp; etp->et_index = index; etp->et_mask = n - 1; etp->et_esmp = esmp; /* Initial descriptor index may be modified by etxo_qcreate */ *addedp = 0; if ((rc = etxop->etxo_qcreate(enp, index, label, esmp, n, id, flags, eep, etp, addedp)) != 0) goto fail2; enp->en_tx_qcount++; *etpp = etp; return (0); fail2: EFSYS_PROBE(fail2); EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qdestroy( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(enp->en_tx_qcount != 0); --enp->en_tx_qcount; etxop->etxo_qdestroy(etp); /* Free the TXQ object */ EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_txq_t), etp); } __checkReturn efx_rc_t efx_tx_qpost( __in efx_txq_t *etp, __in_ecount(n) efx_buffer_t *eb, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if ((rc = etxop->etxo_qpost(etp, eb, n, completed, addedp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qpush( __in efx_txq_t *etp, __in unsigned int added, __in unsigned int pushed) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); etxop->etxo_qpush(etp, added, pushed); } __checkReturn efx_rc_t efx_tx_qpace( __in efx_txq_t *etp, __in unsigned int ns) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if ((rc = etxop->etxo_qpace(etp, ns)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_tx_qflush( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if ((rc = etxop->etxo_qflush(etp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qenable( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); etxop->etxo_qenable(etp); } __checkReturn efx_rc_t efx_tx_qpio_enable( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if (~enp->en_features & EFX_FEATURE_PIO_BUFFERS) { rc = ENOTSUP; goto fail1; } if (etxop->etxo_qpio_enable == NULL) { rc = ENOTSUP; goto fail2; } if ((rc = etxop->etxo_qpio_enable(etp)) != 0) goto fail3; return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qpio_disable( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if (etxop->etxo_qpio_disable != NULL) etxop->etxo_qpio_disable(etp); } __checkReturn efx_rc_t efx_tx_qpio_write( __in efx_txq_t *etp, __in_ecount(buf_length) uint8_t *buffer, __in size_t buf_length, __in size_t pio_buf_offset) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if (etxop->etxo_qpio_write != NULL) { if ((rc = etxop->etxo_qpio_write(etp, buffer, buf_length, pio_buf_offset)) != 0) goto fail1; return (0); } return (ENOTSUP); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_tx_qpio_post( __in efx_txq_t *etp, __in size_t pkt_length, __in unsigned int completed, __inout unsigned int *addedp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if (etxop->etxo_qpio_post != NULL) { if ((rc = etxop->etxo_qpio_post(etp, pkt_length, completed, addedp)) != 0) goto fail1; return (0); } return (ENOTSUP); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_tx_qdesc_post( __in efx_txq_t *etp, __in_ecount(n) efx_desc_t *ed, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; efx_rc_t rc; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); if ((rc = etxop->etxo_qdesc_post(etp, ed, n, completed, addedp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void efx_tx_qdesc_dma_create( __in efx_txq_t *etp, __in efsys_dma_addr_t addr, __in size_t size, __in boolean_t eop, __out efx_desc_t *edp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(etxop->etxo_qdesc_dma_create != NULL); etxop->etxo_qdesc_dma_create(etp, addr, size, eop, edp); } void efx_tx_qdesc_tso_create( __in efx_txq_t *etp, __in uint16_t ipv4_id, __in uint32_t tcp_seq, __in uint8_t tcp_flags, __out efx_desc_t *edp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(etxop->etxo_qdesc_tso_create != NULL); etxop->etxo_qdesc_tso_create(etp, ipv4_id, tcp_seq, tcp_flags, edp); } void efx_tx_qdesc_tso2_create( __in efx_txq_t *etp, __in uint16_t ipv4_id, __in uint32_t tcp_seq, __in uint16_t mss, __out_ecount(count) efx_desc_t *edp, __in int count) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(etxop->etxo_qdesc_tso2_create != NULL); etxop->etxo_qdesc_tso2_create(etp, ipv4_id, tcp_seq, mss, edp, count); } void efx_tx_qdesc_vlantci_create( __in efx_txq_t *etp, __in uint16_t tci, __out efx_desc_t *edp) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); EFSYS_ASSERT(etxop->etxo_qdesc_vlantci_create != NULL); etxop->etxo_qdesc_vlantci_create(etp, tci, edp); } #if EFSYS_OPT_QSTATS void efx_tx_qstats_update( __in efx_txq_t *etp, __inout_ecount(TX_NQSTATS) efsys_stat_t *stat) { efx_nic_t *enp = etp->et_enp; - efx_tx_ops_t *etxop = enp->en_etxop; + const efx_tx_ops_t *etxop = enp->en_etxop; EFSYS_ASSERT3U(etp->et_magic, ==, EFX_TXQ_MAGIC); etxop->etxo_qstats_update(etp, stat); } #endif #if EFSYS_OPT_SIENA static __checkReturn efx_rc_t falconsiena_tx_init( __in efx_nic_t *enp) { efx_oword_t oword; /* * Disable the timer-based TX DMA backoff and allow TX DMA to be * controlled by the RX FIFO fill level (although always allow a * minimal trickle). */ EFX_BAR_READO(enp, FR_AZ_TX_RESERVED_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER, 0xfe); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_RX_SPACER_EN, 1); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_ONE_PKT_PER_Q, 1); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PUSH_EN, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DIS_NON_IP_EV, 1); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_THRESHOLD, 2); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_PREF_WD_TMR, 0x3fffff); /* * Filter all packets less than 14 bytes to avoid parsing * errors. */ EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1); EFX_BAR_WRITEO(enp, FR_AZ_TX_RESERVED_REG, &oword); /* * Do not set TX_NO_EOP_DISC_EN, since it limits packets to 16 * descriptors (which is bad). */ EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_NO_EOP_DISC_EN, 0); EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword); return (0); } #define EFX_TX_DESC(_etp, _addr, _size, _eop, _added) \ do { \ unsigned int id; \ size_t offset; \ efx_qword_t qword; \ \ id = (_added)++ & (_etp)->et_mask; \ offset = id * sizeof (efx_qword_t); \ \ EFSYS_PROBE5(tx_post, unsigned int, (_etp)->et_index, \ unsigned int, id, efsys_dma_addr_t, (_addr), \ size_t, (_size), boolean_t, (_eop)); \ \ EFX_POPULATE_QWORD_4(qword, \ FSF_AZ_TX_KER_CONT, (_eop) ? 0 : 1, \ FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)(_size), \ FSF_AZ_TX_KER_BUF_ADDR_DW0, \ (uint32_t)((_addr) & 0xffffffff), \ FSF_AZ_TX_KER_BUF_ADDR_DW1, \ (uint32_t)((_addr) >> 32)); \ EFSYS_MEM_WRITEQ((_etp)->et_esmp, offset, &qword); \ \ _NOTE(CONSTANTCONDITION) \ } while (B_FALSE) static __checkReturn efx_rc_t falconsiena_tx_qpost( __in efx_txq_t *etp, __in_ecount(n) efx_buffer_t *eb, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp) { unsigned int added = *addedp; unsigned int i; int rc = ENOSPC; if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) goto fail1; for (i = 0; i < n; i++) { efx_buffer_t *ebp = &eb[i]; efsys_dma_addr_t start = ebp->eb_addr; size_t size = ebp->eb_size; efsys_dma_addr_t end = start + size; /* Fragments must not span 4k boundaries. */ EFSYS_ASSERT(P2ROUNDUP(start + 1, 4096) >= end); EFX_TX_DESC(etp, start, size, ebp->eb_eop, added); } EFX_TX_QSTAT_INCR(etp, TX_POST); *addedp = added; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static void falconsiena_tx_qpush( __in efx_txq_t *etp, __in unsigned int added, __in unsigned int pushed) { efx_nic_t *enp = etp->et_enp; uint32_t wptr; efx_dword_t dword; efx_oword_t oword; /* Push the populated descriptors out */ wptr = added & etp->et_mask; EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_DESC_WPTR, wptr); /* Only write the third DWORD */ EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, EFX_OWORD_FIELD(oword, EFX_DWORD_3)); /* Guarantee ordering of memory (descriptors) and PIO (doorbell) */ EFX_DMA_SYNC_QUEUE_FOR_DEVICE(etp->et_esmp, etp->et_mask + 1, wptr, pushed & etp->et_mask); EFSYS_PIO_WRITE_BARRIER(); EFX_BAR_TBL_WRITED3(enp, FR_BZ_TX_DESC_UPD_REGP0, etp->et_index, &dword, B_FALSE); } #define EFX_MAX_PACE_VALUE 20 #define EFX_TX_PACE_CLOCK_BASE 104 static __checkReturn efx_rc_t falconsiena_tx_qpace( __in efx_txq_t *etp, __in unsigned int ns) { efx_nic_t *enp = etp->et_enp; efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_oword_t oword; unsigned int pace_val; unsigned int timer_period; efx_rc_t rc; if (ns == 0) { pace_val = 0; } else { /* * The pace_val to write into the table is s.t * ns <= timer_period * (2 ^ pace_val) */ timer_period = EFX_TX_PACE_CLOCK_BASE / encp->enc_clk_mult; for (pace_val = 1; pace_val <= EFX_MAX_PACE_VALUE; pace_val++) { if ((timer_period << pace_val) >= ns) break; } } if (pace_val > EFX_MAX_PACE_VALUE) { rc = EINVAL; goto fail1; } /* Update the pacing table */ EFX_POPULATE_OWORD_1(oword, FRF_AZ_TX_PACE, pace_val); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_PACE_TBL, etp->et_index, &oword, B_TRUE); return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t falconsiena_tx_qflush( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; efx_oword_t oword; uint32_t label; efx_tx_qpace(etp, 0); label = etp->et_index; /* Flush the queue */ EFX_POPULATE_OWORD_2(oword, FRF_AZ_TX_FLUSH_DESCQ_CMD, 1, FRF_AZ_TX_FLUSH_DESCQ, label); EFX_BAR_WRITEO(enp, FR_AZ_TX_FLUSH_DESCQ_REG, &oword); return (0); } static void falconsiena_tx_qenable( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; efx_oword_t oword; EFX_BAR_TBL_READO(enp, FR_AZ_TX_DESC_PTR_TBL, etp->et_index, &oword, B_TRUE); EFSYS_PROBE5(tx_descq_ptr, unsigned int, etp->et_index, uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_3), uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_2), uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_1), uint32_t, EFX_OWORD_FIELD(oword, EFX_DWORD_0)); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DC_HW_RPTR, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_HW_RPTR, 0); EFX_SET_OWORD_FIELD(oword, FRF_AZ_TX_DESCQ_EN, 1); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL, etp->et_index, &oword, B_TRUE); } static __checkReturn efx_rc_t falconsiena_tx_qcreate( __in efx_nic_t *enp, __in unsigned int index, __in unsigned int label, __in efsys_mem_t *esmp, __in size_t n, __in uint32_t id, __in uint16_t flags, __in efx_evq_t *eep, __in efx_txq_t *etp, __out unsigned int *addedp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_oword_t oword; uint32_t size; efx_rc_t rc; EFX_STATIC_ASSERT(EFX_EV_TX_NLABELS == (1 << FRF_AZ_TX_DESCQ_LABEL_WIDTH)); EFSYS_ASSERT3U(label, <, EFX_EV_TX_NLABELS); EFSYS_ASSERT(ISP2(EFX_TXQ_MAXNDESCS(encp))); EFX_STATIC_ASSERT(ISP2(EFX_TXQ_MINNDESCS)); if (!ISP2(n) || (n < EFX_TXQ_MINNDESCS) || (n > EFX_EVQ_MAXNEVS)) { rc = EINVAL; goto fail1; } if (index >= encp->enc_txq_limit) { rc = EINVAL; goto fail2; } for (size = 0; (1 << size) <= (EFX_TXQ_MAXNDESCS(encp) / EFX_TXQ_MINNDESCS); size++) if ((1 << size) == (int)(n / EFX_TXQ_MINNDESCS)) break; if (id + (1 << size) >= encp->enc_buftbl_limit) { rc = EINVAL; goto fail3; } /* Set up the new descriptor queue */ *addedp = 0; EFX_POPULATE_OWORD_6(oword, FRF_AZ_TX_DESCQ_BUF_BASE_ID, id, FRF_AZ_TX_DESCQ_EVQ_ID, eep->ee_index, FRF_AZ_TX_DESCQ_OWNER_ID, 0, FRF_AZ_TX_DESCQ_LABEL, label, FRF_AZ_TX_DESCQ_SIZE, size, FRF_AZ_TX_DESCQ_TYPE, 0); EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_NON_IP_DROP_DIS, 1); EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_IP_CHKSM_DIS, (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1); EFX_SET_OWORD_FIELD(oword, FRF_BZ_TX_TCP_CHKSM_DIS, (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL, etp->et_index, &oword, B_TRUE); return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t falconsiena_tx_qdesc_post( __in efx_txq_t *etp, __in_ecount(n) efx_desc_t *ed, __in unsigned int n, __in unsigned int completed, __inout unsigned int *addedp) { unsigned int added = *addedp; unsigned int i; efx_rc_t rc; if (added - completed + n > EFX_TXQ_LIMIT(etp->et_mask + 1)) { rc = ENOSPC; goto fail1; } for (i = 0; i < n; i++) { efx_desc_t *edp = &ed[i]; unsigned int id; size_t offset; id = added++ & etp->et_mask; offset = id * sizeof (efx_desc_t); EFSYS_MEM_WRITEQ(etp->et_esmp, offset, &edp->ed_eq); } EFSYS_PROBE3(tx_desc_post, unsigned int, etp->et_index, unsigned int, added, unsigned int, n); EFX_TX_QSTAT_INCR(etp, TX_POST); *addedp = added; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void falconsiena_tx_qdesc_dma_create( __in efx_txq_t *etp, __in efsys_dma_addr_t addr, __in size_t size, __in boolean_t eop, __out efx_desc_t *edp) { /* Fragments must not span 4k boundaries. */ EFSYS_ASSERT(P2ROUNDUP(addr + 1, 4096) >= addr + size); EFSYS_PROBE4(tx_desc_dma_create, unsigned int, etp->et_index, efsys_dma_addr_t, addr, size_t, size, boolean_t, eop); EFX_POPULATE_QWORD_4(edp->ed_eq, FSF_AZ_TX_KER_CONT, eop ? 0 : 1, FSF_AZ_TX_KER_BYTE_COUNT, (uint32_t)size, FSF_AZ_TX_KER_BUF_ADDR_DW0, (uint32_t)(addr & 0xffffffff), FSF_AZ_TX_KER_BUF_ADDR_DW1, (uint32_t)(addr >> 32)); } #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_QSTATS #if EFSYS_OPT_NAMES /* START MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock 9d8d26a0a5e2c453 */ static const char *__efx_tx_qstat_name[] = { "post", "post_pio", }; /* END MKCONFIG GENERATED EfxTransmitQueueStatNamesBlock */ const char * efx_tx_qstat_name( __in efx_nic_t *enp, __in unsigned int id) { _NOTE(ARGUNUSED(enp)) EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(id, <, TX_NQSTATS); return (__efx_tx_qstat_name[id]); } #endif /* EFSYS_OPT_NAMES */ #endif /* EFSYS_OPT_QSTATS */ #if EFSYS_OPT_SIENA #if EFSYS_OPT_QSTATS static void falconsiena_tx_qstats_update( __in efx_txq_t *etp, __inout_ecount(TX_NQSTATS) efsys_stat_t *stat) { unsigned int id; for (id = 0; id < TX_NQSTATS; id++) { efsys_stat_t *essp = &stat[id]; EFSYS_STAT_INCR(essp, etp->et_stat[id]); etp->et_stat[id] = 0; } } #endif /* EFSYS_OPT_QSTATS */ static void falconsiena_tx_qdestroy( __in efx_txq_t *etp) { efx_nic_t *enp = etp->et_enp; efx_oword_t oword; /* Purge descriptor queue */ EFX_ZERO_OWORD(oword); EFX_BAR_TBL_WRITEO(enp, FR_AZ_TX_DESC_PTR_TBL, etp->et_index, &oword, B_TRUE); } static void falconsiena_tx_fini( __in efx_nic_t *enp) { _NOTE(ARGUNUSED(enp)) } #endif /* EFSYS_OPT_SIENA */ Index: head/sys/dev/sfxge/common/efx_vpd.c =================================================================== --- head/sys/dev/sfxge/common/efx_vpd.c (revision 299516) +++ head/sys/dev/sfxge/common/efx_vpd.c (revision 299517) @@ -1,1015 +1,1015 @@ /*- * Copyright (c) 2009-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_VPD #define TAG_TYPE_LBN 7 #define TAG_TYPE_WIDTH 1 #define TAG_TYPE_LARGE_ITEM_DECODE 1 #define TAG_TYPE_SMALL_ITEM_DECODE 0 #define TAG_SMALL_ITEM_NAME_LBN 3 #define TAG_SMALL_ITEM_NAME_WIDTH 4 #define TAG_SMALL_ITEM_SIZE_LBN 0 #define TAG_SMALL_ITEM_SIZE_WIDTH 3 #define TAG_LARGE_ITEM_NAME_LBN 0 #define TAG_LARGE_ITEM_NAME_WIDTH 7 #define TAG_NAME_END_DECODE 0x0f #define TAG_NAME_ID_STRING_DECODE 0x02 #define TAG_NAME_VPD_R_DECODE 0x10 #define TAG_NAME_VPD_W_DECODE 0x11 #if EFSYS_OPT_SIENA -static efx_vpd_ops_t __efx_vpd_siena_ops = { +static const efx_vpd_ops_t __efx_vpd_siena_ops = { siena_vpd_init, /* evpdo_init */ siena_vpd_size, /* evpdo_size */ siena_vpd_read, /* evpdo_read */ siena_vpd_verify, /* evpdo_verify */ siena_vpd_reinit, /* evpdo_reinit */ siena_vpd_get, /* evpdo_get */ siena_vpd_set, /* evpdo_set */ siena_vpd_next, /* evpdo_next */ siena_vpd_write, /* evpdo_write */ siena_vpd_fini, /* evpdo_fini */ }; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD -static efx_vpd_ops_t __efx_vpd_ef10_ops = { +static const efx_vpd_ops_t __efx_vpd_ef10_ops = { ef10_vpd_init, /* evpdo_init */ ef10_vpd_size, /* evpdo_size */ ef10_vpd_read, /* evpdo_read */ ef10_vpd_verify, /* evpdo_verify */ ef10_vpd_reinit, /* evpdo_reinit */ ef10_vpd_get, /* evpdo_get */ ef10_vpd_set, /* evpdo_set */ ef10_vpd_next, /* evpdo_next */ ef10_vpd_write, /* evpdo_write */ ef10_vpd_fini, /* evpdo_fini */ }; #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ __checkReturn efx_rc_t efx_vpd_init( __in efx_nic_t *enp) { - efx_vpd_ops_t *evpdop; + const efx_vpd_ops_t *evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_VPD)); switch (enp->en_family) { #if EFSYS_OPT_SIENA case EFX_FAMILY_SIENA: - evpdop = (efx_vpd_ops_t *)&__efx_vpd_siena_ops; + evpdop = &__efx_vpd_siena_ops; break; #endif /* EFSYS_OPT_SIENA */ #if EFSYS_OPT_HUNTINGTON case EFX_FAMILY_HUNTINGTON: - evpdop = (efx_vpd_ops_t *)&__efx_vpd_ef10_ops; + evpdop = &__efx_vpd_ef10_ops; break; #endif /* EFSYS_OPT_HUNTINGTON */ #if EFSYS_OPT_MEDFORD case EFX_FAMILY_MEDFORD: - evpdop = (efx_vpd_ops_t *)&__efx_vpd_ef10_ops; + evpdop = &__efx_vpd_ef10_ops; break; #endif /* EFSYS_OPT_MEDFORD */ default: EFSYS_ASSERT(0); rc = ENOTSUP; goto fail1; } if (evpdop->evpdo_init != NULL) { if ((rc = evpdop->evpdo_init(enp)) != 0) goto fail2; } enp->en_evpdop = evpdop; enp->en_mod_flags |= EFX_MOD_VPD; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_size( __in efx_nic_t *enp, __out size_t *sizep) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if ((rc = evpdop->evpdo_size(enp, sizep)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_read( __in efx_nic_t *enp, __out_bcount(size) caddr_t data, __in size_t size) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if ((rc = evpdop->evpdo_read(enp, data, size)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_verify( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if ((rc = evpdop->evpdo_verify(enp, data, size)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_reinit( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if (evpdop->evpdo_reinit == NULL) { rc = ENOTSUP; goto fail1; } if ((rc = evpdop->evpdo_reinit(enp, data, size)) != 0) goto fail2; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_get( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size, __inout efx_vpd_value_t *evvp) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if ((rc = evpdop->evpdo_get(enp, data, size, evvp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_set( __in efx_nic_t *enp, __inout_bcount(size) caddr_t data, __in size_t size, __in efx_vpd_value_t *evvp) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if ((rc = evpdop->evpdo_set(enp, data, size, evvp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_next( __in efx_nic_t *enp, __inout_bcount(size) caddr_t data, __in size_t size, __out efx_vpd_value_t *evvp, __inout unsigned int *contp) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if ((rc = evpdop->evpdo_next(enp, data, size, evvp, contp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_write( __in efx_nic_t *enp, __in_bcount(size) caddr_t data, __in size_t size) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if ((rc = evpdop->evpdo_write(enp, data, size)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_vpd_next_tag( __in caddr_t data, __in size_t size, __inout unsigned int *offsetp, __out efx_vpd_tag_t *tagp, __out uint16_t *lengthp) { efx_byte_t byte; efx_word_t word; uint8_t name; uint16_t length; size_t headlen; efx_rc_t rc; if (*offsetp >= size) { rc = EFAULT; goto fail1; } EFX_POPULATE_BYTE_1(byte, EFX_BYTE_0, data[*offsetp]); switch (EFX_BYTE_FIELD(byte, TAG_TYPE)) { case TAG_TYPE_SMALL_ITEM_DECODE: headlen = 1; name = EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_NAME); length = (uint16_t)EFX_BYTE_FIELD(byte, TAG_SMALL_ITEM_SIZE); break; case TAG_TYPE_LARGE_ITEM_DECODE: headlen = 3; if (*offsetp + headlen > size) { rc = EFAULT; goto fail2; } name = EFX_BYTE_FIELD(byte, TAG_LARGE_ITEM_NAME); EFX_POPULATE_WORD_2(word, EFX_BYTE_0, data[*offsetp + 1], EFX_BYTE_1, data[*offsetp + 2]); length = EFX_WORD_FIELD(word, EFX_WORD_0); break; default: rc = EFAULT; goto fail2; } if (*offsetp + headlen + length > size) { rc = EFAULT; goto fail3; } EFX_STATIC_ASSERT(TAG_NAME_END_DECODE == EFX_VPD_END); EFX_STATIC_ASSERT(TAG_NAME_ID_STRING_DECODE == EFX_VPD_ID); EFX_STATIC_ASSERT(TAG_NAME_VPD_R_DECODE == EFX_VPD_RO); EFX_STATIC_ASSERT(TAG_NAME_VPD_W_DECODE == EFX_VPD_RW); if (name != EFX_VPD_END && name != EFX_VPD_ID && name != EFX_VPD_RO) { rc = EFAULT; goto fail4; } *tagp = name; *lengthp = length; *offsetp += headlen; 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_vpd_next_keyword( __in_bcount(size) caddr_t tag, __in size_t size, __in unsigned int pos, __out efx_vpd_keyword_t *keywordp, __out uint8_t *lengthp) { efx_vpd_keyword_t keyword; uint8_t length; efx_rc_t rc; if (pos + 3U > size) { rc = EFAULT; goto fail1; } keyword = EFX_VPD_KEYWORD(tag[pos], tag[pos + 1]); length = tag[pos + 2]; if (length == 0 || pos + 3U + length > size) { rc = EFAULT; goto fail2; } *keywordp = keyword; *lengthp = length; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_hunk_length( __in_bcount(size) caddr_t data, __in size_t size, __out size_t *lengthp) { efx_vpd_tag_t tag; unsigned int offset; uint16_t taglen; efx_rc_t rc; offset = 0; _NOTE(CONSTANTCONDITION) while (1) { if ((rc = efx_vpd_next_tag(data, size, &offset, &tag, &taglen)) != 0) goto fail1; offset += taglen; if (tag == EFX_VPD_END) break; } *lengthp = offset; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_hunk_verify( __in_bcount(size) caddr_t data, __in size_t size, __out_opt boolean_t *cksummedp) { efx_vpd_tag_t tag; efx_vpd_keyword_t keyword; unsigned int offset; unsigned int pos; unsigned int i; uint16_t taglen; uint8_t keylen; uint8_t cksum; boolean_t cksummed = B_FALSE; efx_rc_t rc; /* * Parse every tag,keyword in the existing VPD. If the csum is present, * the assert it is correct, and is the final keyword in the RO block. */ offset = 0; _NOTE(CONSTANTCONDITION) while (1) { if ((rc = efx_vpd_next_tag(data, size, &offset, &tag, &taglen)) != 0) goto fail1; if (tag == EFX_VPD_END) break; else if (tag == EFX_VPD_ID) goto done; for (pos = 0; pos != taglen; pos += 3 + keylen) { /* RV keyword must be the last in the block */ if (cksummed) { rc = EFAULT; goto fail2; } if ((rc = efx_vpd_next_keyword(data + offset, taglen, pos, &keyword, &keylen)) != 0) goto fail3; if (keyword == EFX_VPD_KEYWORD('R', 'V')) { cksum = 0; for (i = 0; i < offset + pos + 4; i++) cksum += data[i]; if (cksum != 0) { rc = EFAULT; goto fail4; } cksummed = B_TRUE; } } done: offset += taglen; } if (!cksummed) { rc = EFAULT; goto fail5; } if (cksummedp != NULL) *cksummedp = cksummed; 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 uint8_t __efx_vpd_blank_pid[] = { /* Large resource type ID length 1 */ 0x82, 0x01, 0x00, /* Product name ' ' */ 0x32, }; static uint8_t __efx_vpd_blank_r[] = { /* Large resource type VPD-R length 4 */ 0x90, 0x04, 0x00, /* RV keyword length 1 */ 'R', 'V', 0x01, /* RV payload checksum */ 0x00, }; __checkReturn efx_rc_t efx_vpd_hunk_reinit( __in_bcount(size) caddr_t data, __in size_t size, __in boolean_t wantpid) { unsigned int offset = 0; unsigned int pos; efx_byte_t byte; uint8_t cksum; efx_rc_t rc; if (size < 0x100) { rc = ENOSPC; goto fail1; } if (wantpid) { memcpy(data + offset, __efx_vpd_blank_pid, sizeof (__efx_vpd_blank_pid)); offset += sizeof (__efx_vpd_blank_pid); } memcpy(data + offset, __efx_vpd_blank_r, sizeof (__efx_vpd_blank_r)); offset += sizeof (__efx_vpd_blank_r); /* Update checksum */ cksum = 0; for (pos = 0; pos < offset; pos++) cksum += data[pos]; data[offset - 1] -= cksum; /* Append trailing tag */ EFX_POPULATE_BYTE_3(byte, TAG_TYPE, TAG_TYPE_SMALL_ITEM_DECODE, TAG_SMALL_ITEM_NAME, TAG_NAME_END_DECODE, TAG_SMALL_ITEM_SIZE, 0); data[offset] = EFX_BYTE_FIELD(byte, EFX_BYTE_0); offset++; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_hunk_next( __in_bcount(size) caddr_t data, __in size_t size, __out efx_vpd_tag_t *tagp, __out efx_vpd_keyword_t *keywordp, __out_opt unsigned int *payloadp, __out_opt uint8_t *paylenp, __inout unsigned int *contp) { efx_vpd_tag_t tag; efx_vpd_keyword_t keyword = 0; unsigned int offset; unsigned int pos; unsigned int index; uint16_t taglen; uint8_t keylen; uint8_t paylen; efx_rc_t rc; offset = index = 0; _NOTE(CONSTANTCONDITION) while (1) { if ((rc = efx_vpd_next_tag(data, size, &offset, &tag, &taglen)) != 0) goto fail1; if (tag == EFX_VPD_END) { keyword = 0; paylen = 0; index = 0; break; } if (tag == EFX_VPD_ID) { if (index++ == *contp) { EFSYS_ASSERT3U(taglen, <, 0x100); keyword = 0; paylen = (uint8_t)MIN(taglen, 0xff); goto done; } } else { for (pos = 0; pos != taglen; pos += 3 + keylen) { if ((rc = efx_vpd_next_keyword(data + offset, taglen, pos, &keyword, &keylen)) != 0) goto fail2; if (index++ == *contp) { offset += pos + 3; paylen = keylen; goto done; } } } offset += taglen; } done: *tagp = tag; *keywordp = keyword; if (payloadp != NULL) *payloadp = offset; if (paylenp != NULL) *paylenp = paylen; *contp = index; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_hunk_get( __in_bcount(size) caddr_t data, __in size_t size, __in efx_vpd_tag_t tag, __in efx_vpd_keyword_t keyword, __out unsigned int *payloadp, __out uint8_t *paylenp) { efx_vpd_tag_t itag; efx_vpd_keyword_t ikeyword; unsigned int offset; unsigned int pos; uint16_t taglen; uint8_t keylen; efx_rc_t rc; offset = 0; _NOTE(CONSTANTCONDITION) while (1) { if ((rc = efx_vpd_next_tag(data, size, &offset, &itag, &taglen)) != 0) goto fail1; if (itag == EFX_VPD_END) break; if (itag == tag) { if (itag == EFX_VPD_ID) { EFSYS_ASSERT3U(taglen, <, 0x100); *paylenp = (uint8_t)MIN(taglen, 0xff); *payloadp = offset; return (0); } for (pos = 0; pos != taglen; pos += 3 + keylen) { if ((rc = efx_vpd_next_keyword(data + offset, taglen, pos, &ikeyword, &keylen)) != 0) goto fail2; if (ikeyword == keyword) { *paylenp = keylen; *payloadp = offset + pos + 3; return (0); } } } offset += taglen; } /* Not an error */ return (ENOENT); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_vpd_hunk_set( __in_bcount(size) caddr_t data, __in size_t size, __in efx_vpd_value_t *evvp) { efx_word_t word; efx_vpd_tag_t tag; efx_vpd_keyword_t keyword; unsigned int offset; unsigned int pos; unsigned int taghead; unsigned int source; unsigned int dest; unsigned int i; uint16_t taglen; uint8_t keylen; uint8_t cksum; size_t used; efx_rc_t rc; switch (evvp->evv_tag) { case EFX_VPD_ID: if (evvp->evv_keyword != 0) { rc = EINVAL; goto fail1; } /* Can't delete the ID keyword */ if (evvp->evv_length == 0) { rc = EINVAL; goto fail1; } break; case EFX_VPD_RO: if (evvp->evv_keyword == EFX_VPD_KEYWORD('R', 'V')) { rc = EINVAL; goto fail1; } break; default: rc = EINVAL; goto fail1; } /* Determine total size of all current tags */ if ((rc = efx_vpd_hunk_length(data, size, &used)) != 0) goto fail2; offset = 0; _NOTE(CONSTANTCONDITION) while (1) { taghead = offset; if ((rc = efx_vpd_next_tag(data, size, &offset, &tag, &taglen)) != 0) goto fail3; if (tag == EFX_VPD_END) break; else if (tag != evvp->evv_tag) { offset += taglen; continue; } /* We only support modifying large resource tags */ if (offset - taghead != 3) { rc = EINVAL; goto fail4; } /* * Work out the offset of the byte immediately after the * old (=source) and new (=dest) new keyword/tag */ pos = 0; if (tag == EFX_VPD_ID) { source = offset + taglen; dest = offset + evvp->evv_length; goto check_space; } EFSYS_ASSERT3U(tag, ==, EFX_VPD_RO); source = dest = 0; for (pos = 0; pos != taglen; pos += 3 + keylen) { if ((rc = efx_vpd_next_keyword(data + offset, taglen, pos, &keyword, &keylen)) != 0) goto fail5; if (keyword == evvp->evv_keyword && evvp->evv_length == 0) { /* Deleting this keyword */ source = offset + pos + 3 + keylen; dest = offset + pos; break; } else if (keyword == evvp->evv_keyword) { /* Adjusting this keyword */ source = offset + pos + 3 + keylen; dest = offset + pos + 3 + evvp->evv_length; break; } else if (keyword == EFX_VPD_KEYWORD('R', 'V')) { /* The RV keyword must be at the end */ EFSYS_ASSERT3U(pos + 3 + keylen, ==, taglen); /* * The keyword doesn't already exist. If the * user deleting a non-existant keyword then * this is a no-op. */ if (evvp->evv_length == 0) return (0); /* Insert this keyword before the RV keyword */ source = offset + pos; dest = offset + pos + 3 + evvp->evv_length; break; } } check_space: if (used + dest > size + source) { rc = ENOSPC; goto fail6; } /* Move trailing data */ (void) memmove(data + dest, data + source, used - source); /* Copy contents */ memcpy(data + dest - evvp->evv_length, evvp->evv_value, evvp->evv_length); /* Insert new keyword header if required */ if (tag != EFX_VPD_ID && evvp->evv_length > 0) { EFX_POPULATE_WORD_1(word, EFX_WORD_0, evvp->evv_keyword); data[offset + pos + 0] = EFX_WORD_FIELD(word, EFX_BYTE_0); data[offset + pos + 1] = EFX_WORD_FIELD(word, EFX_BYTE_1); data[offset + pos + 2] = evvp->evv_length; } /* Modify tag length (large resource type) */ taglen += (dest - source); EFX_POPULATE_WORD_1(word, EFX_WORD_0, taglen); data[offset - 2] = EFX_WORD_FIELD(word, EFX_BYTE_0); data[offset - 1] = EFX_WORD_FIELD(word, EFX_BYTE_1); goto checksum; } /* Unable to find the matching tag */ rc = ENOENT; goto fail7; checksum: /* Find the RV tag, and update the checksum */ offset = 0; _NOTE(CONSTANTCONDITION) while (1) { if ((rc = efx_vpd_next_tag(data, size, &offset, &tag, &taglen)) != 0) goto fail8; if (tag == EFX_VPD_END) break; if (tag == EFX_VPD_RO) { for (pos = 0; pos != taglen; pos += 3 + keylen) { if ((rc = efx_vpd_next_keyword(data + offset, taglen, pos, &keyword, &keylen)) != 0) goto fail9; if (keyword == EFX_VPD_KEYWORD('R', 'V')) { cksum = 0; for (i = 0; i < offset + pos + 3; i++) cksum += data[i]; data[i] = -cksum; break; } } } offset += taglen; } /* Zero out the unused portion */ (void) memset(data + offset + taglen, 0xff, size - offset - taglen); return (0); fail9: EFSYS_PROBE(fail9); fail8: EFSYS_PROBE(fail8); fail7: EFSYS_PROBE(fail7); fail6: EFSYS_PROBE(fail6); 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); } void efx_vpd_fini( __in efx_nic_t *enp) { - efx_vpd_ops_t *evpdop = enp->en_evpdop; + const efx_vpd_ops_t *evpdop = enp->en_evpdop; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_VPD); if (evpdop->evpdo_fini != NULL) evpdop->evpdo_fini(enp); enp->en_evpdop = NULL; enp->en_mod_flags &= ~EFX_MOD_VPD; } #endif /* EFSYS_OPT_VPD */ Index: head/sys/dev/sfxge/common/hunt_mac.c =================================================================== --- head/sys/dev/sfxge/common/hunt_mac.c (revision 299516) +++ head/sys/dev/sfxge/common/hunt_mac.c (revision 299517) @@ -1,752 +1,752 @@ /*- * Copyright (c) 2012-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_HUNTINGTON __checkReturn efx_rc_t ef10_mac_poll( __in efx_nic_t *enp, __out efx_link_mode_t *link_modep) { efx_port_t *epp = &(enp->en_port); ef10_link_state_t els; efx_rc_t rc; if ((rc = ef10_phy_get_link(enp, &els)) != 0) goto fail1; epp->ep_adv_cap_mask = els.els_adv_cap_mask; epp->ep_fcntl = els.els_fcntl; *link_modep = els.els_link_mode; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); *link_modep = EFX_LINK_UNKNOWN; return (rc); } __checkReturn efx_rc_t ef10_mac_up( __in efx_nic_t *enp, __out boolean_t *mac_upp) { ef10_link_state_t els; efx_rc_t rc; /* * Because EF10 doesn't *require* polling, we can't rely on * ef10_mac_poll() being executed to populate epp->ep_mac_up. */ if ((rc = ef10_phy_get_link(enp, &els)) != 0) goto fail1; *mac_upp = els.els_mac_up; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } /* * EF10 adapters use MC_CMD_VADAPTOR_SET_MAC to set the * MAC address; the address field in MC_CMD_SET_MAC has no * effect. * MC_CMD_VADAPTOR_SET_MAC requires mac-spoofing privilege and * the port to have no filters or queues active. */ static __checkReturn efx_rc_t efx_mcdi_vadapter_set_mac( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_VADAPTOR_SET_MAC_IN_LEN, MC_CMD_VADAPTOR_SET_MAC_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_VADAPTOR_SET_MAC; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_VADAPTOR_SET_MAC_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_VADAPTOR_SET_MAC_OUT_LEN; MCDI_IN_SET_DWORD(req, VADAPTOR_SET_MAC_IN_UPSTREAM_PORT_ID, enp->en_vport_id); EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, VADAPTOR_SET_MAC_IN_MACADDR), epp->ep_mac_addr); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_mac_addr_set( __in efx_nic_t *enp) { efx_rc_t rc; if ((rc = efx_mcdi_vadapter_set_mac(enp)) != 0) { if (rc != ENOTSUP) goto fail1; /* * Fallback for older Huntington firmware without Vadapter * support. */ if ((rc = ef10_mac_reconfigure(enp)) != 0) goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_mtu_set( __in efx_nic_t *enp, __in uint32_t mtu) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_SET_MAC_EXT_IN_LEN, MC_CMD_SET_MAC_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_SET_MAC; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_SET_MAC_EXT_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN; /* Only configure the MTU in this call to MC_CMD_SET_MAC */ MCDI_IN_SET_DWORD(req, SET_MAC_EXT_IN_MTU, mtu); MCDI_IN_POPULATE_DWORD_1(req, SET_MAC_EXT_IN_CONTROL, SET_MAC_EXT_IN_CFG_MTU, 1); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_mac_pdu_set( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_rc_t rc; if (encp->enc_enhanced_set_mac_supported) { if ((rc = efx_mcdi_mtu_set(enp, epp->ep_mac_pdu)) != 0) goto fail1; } else { /* * Fallback for older Huntington firmware, which always * configure all of the parameters to MC_CMD_SET_MAC. This isn't * suitable for setting the MTU on unpriviliged functions. */ if ((rc = ef10_mac_reconfigure(enp)) != 0) goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_mac_reconfigure( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_SET_MAC_IN_LEN, MC_CMD_SET_MAC_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_SET_MAC; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_SET_MAC_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN; MCDI_IN_SET_DWORD(req, SET_MAC_IN_MTU, epp->ep_mac_pdu); MCDI_IN_SET_DWORD(req, SET_MAC_IN_DRAIN, epp->ep_mac_drain ? 1 : 0); EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, SET_MAC_IN_ADDR), epp->ep_mac_addr); /* * Note: The Huntington MAC does not support REJECT_BRDCST. * The REJECT_UNCST flag will also prevent multicast traffic * from reaching the filters. As Huntington filters drop any * traffic that does not match a filter it is ok to leave the * MAC running in promiscuous mode. See bug41141. * * FIXME: Does REJECT_UNCST behave the same way on Medford? */ MCDI_IN_POPULATE_DWORD_2(req, SET_MAC_IN_REJECT, SET_MAC_IN_REJECT_UNCST, 0, SET_MAC_IN_REJECT_BRDCST, 0); /* * Flow control, whether it is auto-negotiated or not, * is set via the PHY advertised capabilities. When set to * automatic the MAC will use the PHY settings to determine * the flow control settings. */ MCDI_IN_SET_DWORD(req, SET_MAC_IN_FCNTL, MC_CMD_FCNTL_AUTO); /* Do not include the Ethernet frame checksum in RX packets */ MCDI_IN_POPULATE_DWORD_1(req, SET_MAC_IN_FLAGS, SET_MAC_IN_FLAG_INCLUDE_FCS, 0); efx_mcdi_execute_quiet(enp, &req); if (req.emr_rc != 0) { /* * Unprivileged functions cannot control link state, * but still need to configure filters. */ if (req.emr_rc != EACCES) { rc = req.emr_rc; goto fail1; } } /* * Apply the filters for the MAC configuration. * If the NIC isn't ready to accept filters this may * return success without setting anything. */ rc = efx_filter_reconfigure(enp, epp->ep_mac_addr, epp->ep_all_unicst, epp->ep_mulcst, epp->ep_all_mulcst, epp->ep_brdcst, epp->ep_mulcst_addr_list, epp->ep_mulcst_addr_count); return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_mac_multicast_list_set( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); - efx_mac_ops_t *emop = epp->ep_emop; + const efx_mac_ops_t *emop = epp->ep_emop; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); if ((rc = emop->emo_reconfigure(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_mac_filter_default_rxq_set( __in efx_nic_t *enp, __in efx_rxq_t *erp, __in boolean_t using_rss) { efx_port_t *epp = &(enp->en_port); efx_rxq_t *old_rxq; boolean_t old_using_rss; efx_rc_t rc; ef10_filter_get_default_rxq(enp, &old_rxq, &old_using_rss); ef10_filter_default_rxq_set(enp, erp, using_rss); rc = efx_filter_reconfigure(enp, epp->ep_mac_addr, epp->ep_all_unicst, epp->ep_mulcst, epp->ep_all_mulcst, epp->ep_brdcst, epp->ep_mulcst_addr_list, epp->ep_mulcst_addr_count); if (rc != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); ef10_filter_default_rxq_set(enp, old_rxq, old_using_rss); return (rc); } void ef10_mac_filter_default_rxq_clear( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); ef10_filter_default_rxq_clear(enp); efx_filter_reconfigure(enp, epp->ep_mac_addr, epp->ep_all_unicst, epp->ep_mulcst, epp->ep_all_mulcst, epp->ep_brdcst, epp->ep_mulcst_addr_list, epp->ep_mulcst_addr_count); } #if EFSYS_OPT_LOOPBACK __checkReturn efx_rc_t ef10_mac_loopback_set( __in efx_nic_t *enp, __in efx_link_mode_t link_mode, __in efx_loopback_type_t loopback_type) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; efx_loopback_type_t old_loopback_type; efx_link_mode_t old_loopback_link_mode; efx_rc_t rc; /* The PHY object handles this on EF10 */ old_loopback_type = epp->ep_loopback_type; old_loopback_link_mode = epp->ep_loopback_link_mode; epp->ep_loopback_type = loopback_type; epp->ep_loopback_link_mode = link_mode; if ((rc = epop->epo_reconfigure(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); epp->ep_loopback_type = old_loopback_type; epp->ep_loopback_link_mode = old_loopback_link_mode; return (rc); } #endif /* EFSYS_OPT_LOOPBACK */ #if EFSYS_OPT_MAC_STATS #define EF10_MAC_STAT_READ(_esmp, _field, _eqp) \ EFSYS_MEM_READQ((_esmp), (_field) * sizeof (efx_qword_t), _eqp) __checkReturn efx_rc_t ef10_mac_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_MAC_NSTATS) efsys_stat_t *stat, __inout_opt uint32_t *generationp) { efx_qword_t value; efx_qword_t generation_start; efx_qword_t generation_end; _NOTE(ARGUNUSED(enp)) /* Read END first so we don't race with the MC */ EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_END, &generation_end); EFSYS_MEM_READ_BARRIER(); /* TX */ EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_CONTROL_PKTS, &value); EFSYS_STAT_SUBR_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PAUSE_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PAUSE_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_UNICAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_UNICST_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTICAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULTICST_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BROADCAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_BRDCST_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_OCTETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LT64_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_64_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_65_TO_127_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_65_TO_127_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_128_TO_255_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_128_TO_255_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_256_TO_511_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_256_TO_511_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_512_TO_1023_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_512_TO_1023_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_1024_TO_15XX_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_1024_TO_15XX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_GTJUMBO_PKTS, &value); EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BAD_FCS_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_ERRORS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_SGL_COL_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULT_COL_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_COL_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LATE_COLLISION_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LATE_COL_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_DEFERRED_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_DEF_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_DEF_PKTS]), &value); /* RX */ EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_OCTETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNICAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_UNICST_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MULTICAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MULTICST_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BROADCAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_BRDCST_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PAUSE_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PAUSE_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNDERSIZE_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_64_PKTS, &value); EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_65_TO_127_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_65_TO_127_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_128_TO_255_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_128_TO_255_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_256_TO_511_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_256_TO_511_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_512_TO_1023_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_512_TO_1023_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_1024_TO_15XX_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_1024_TO_15XX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_GTJUMBO_PKTS, &value); EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BAD_FCS_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FCS_ERRORS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_OVERFLOW_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_DROP_EVENTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_FALSE_CARRIER_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FALSE_CARRIER_ERRORS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_SYMBOL_ERRORS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_ALIGN_ERROR_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_ALIGN_ERRORS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_INTERNAL_ERRORS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_JABBER_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_JABBER_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_CHAR_ERR, &value); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_CHAR_ERR]), &(value.eq_dword[0])); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_CHAR_ERR]), &(value.eq_dword[1])); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_CHAR_ERR, &value); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_CHAR_ERR]), &(value.eq_dword[0])); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_CHAR_ERR]), &(value.eq_dword[1])); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_DISP_ERR, &value); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_DISP_ERR]), &(value.eq_dword[0])); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_DISP_ERR]), &(value.eq_dword[1])); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_DISP_ERR, &value); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_DISP_ERR]), &(value.eq_dword[0])); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_DISP_ERR]), &(value.eq_dword[1])); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MATCH_FAULT, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MATCH_FAULT]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_NODESC_DROPS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_NODESC_DROP_CNT]), &value); /* Packet memory (EF10 only) */ EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_BB_OVERFLOW, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_BB_OVERFLOW]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_BB_OVERFLOW, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_BB_OVERFLOW]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_VFIFO_FULL, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_VFIFO_FULL]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_VFIFO_FULL, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_VFIFO_FULL]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_TRUNC_QBB, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_TRUNC_QBB]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_QBB, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_QBB]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_PM_DISCARD_MAPPING, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_PM_DISCARD_MAPPING]), &value); /* RX datapath */ EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_Q_DISABLED_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_Q_DISABLED_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_DI_DROPPED_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_DI_DROPPED_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_STREAMING_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_STREAMING_PKTS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_HLB_FETCH_CONDITIONS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_HLB_FETCH]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_RXDP_HLB_WAIT_CONDITIONS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RXDP_HLB_WAIT]), &value); /* VADAPTER RX */ EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_UNICAST_PACKETS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_UNICAST_PACKETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_UNICAST_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_UNICAST_BYTES]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_MULTICAST_PACKETS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_MULTICAST_PACKETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_MULTICAST_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_MULTICAST_BYTES]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BROADCAST_PACKETS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BROADCAST_PACKETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BROADCAST_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BROADCAST_BYTES]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BAD_PACKETS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BAD_PACKETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_BAD_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_BAD_BYTES]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_RX_OVERFLOW, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_RX_OVERFLOW]), &value); /* VADAPTER TX */ EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_UNICAST_PACKETS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_UNICAST_PACKETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_UNICAST_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_UNICAST_BYTES]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_MULTICAST_PACKETS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_MULTICAST_PACKETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_MULTICAST_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_MULTICAST_BYTES]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BROADCAST_PACKETS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BROADCAST_PACKETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BROADCAST_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BROADCAST_BYTES]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BAD_PACKETS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BAD_PACKETS]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_BAD_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_BAD_BYTES]), &value); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_VADAPTER_TX_OVERFLOW, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_VADAPTER_TX_OVERFLOW]), &value); EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE); EFSYS_MEM_READ_BARRIER(); EF10_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_START, &generation_start); /* Check that we didn't read the stats in the middle of a DMA */ /* Not a good enough check ? */ if (memcmp(&generation_start, &generation_end, sizeof (generation_start))) return (EAGAIN); if (generationp) *generationp = EFX_QWORD_FIELD(generation_start, EFX_DWORD_0); return (0); } #endif /* EFSYS_OPT_MAC_STATS */ #endif /* EFSYS_OPT_HUNTINGTON */ Index: head/sys/dev/sfxge/common/hunt_nic.c =================================================================== --- head/sys/dev/sfxge/common/hunt_nic.c (revision 299516) +++ head/sys/dev/sfxge/common/hunt_nic.c (revision 299517) @@ -1,1897 +1,1897 @@ /*- * Copyright (c) 2012-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_MON_MCDI #include "mcdi_mon.h" #endif #if EFSYS_OPT_HUNTINGTON #include "ef10_tlv_layout.h" __checkReturn efx_rc_t efx_mcdi_get_port_assignment( __in efx_nic_t *enp, __out uint32_t *portp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN, MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN)]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_PORT_ASSIGNMENT; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_PORT_ASSIGNMENT_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_PORT_ASSIGNMENT_OUT_LEN) { rc = EMSGSIZE; goto fail2; } *portp = MCDI_OUT_DWORD(req, GET_PORT_ASSIGNMENT_OUT_PORT); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_get_port_modes( __in efx_nic_t *enp, __out uint32_t *modesp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_PORT_MODES_IN_LEN, MC_CMD_GET_PORT_MODES_OUT_LEN)]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_PORT_MODES; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_PORT_MODES_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_PORT_MODES_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } /* * Require only Modes and DefaultMode fields. * (CurrentMode field was added for Medford) */ if (req.emr_out_length_used < MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST) { rc = EMSGSIZE; goto fail2; } *modesp = MCDI_OUT_DWORD(req, GET_PORT_MODES_OUT_MODES); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_vadaptor_alloc( __in efx_nic_t *enp, __in uint32_t port_id) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_VADAPTOR_ALLOC_IN_LEN, MC_CMD_VADAPTOR_ALLOC_OUT_LEN)]; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_vport_id, ==, EVB_PORT_ID_NULL); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_VADAPTOR_ALLOC; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_VADAPTOR_ALLOC_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_VADAPTOR_ALLOC_OUT_LEN; MCDI_IN_SET_DWORD(req, VADAPTOR_ALLOC_IN_UPSTREAM_PORT_ID, port_id); MCDI_IN_POPULATE_DWORD_1(req, VADAPTOR_ALLOC_IN_FLAGS, VADAPTOR_ALLOC_IN_FLAG_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED, enp->en_nic_cfg.enc_allow_set_mac_with_installed_filters ? 1 : 0); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_vadaptor_free( __in efx_nic_t *enp, __in uint32_t port_id) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_VADAPTOR_FREE_IN_LEN, MC_CMD_VADAPTOR_FREE_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_VADAPTOR_FREE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_VADAPTOR_FREE_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_VADAPTOR_FREE_OUT_LEN; MCDI_IN_SET_DWORD(req, VADAPTOR_FREE_IN_UPSTREAM_PORT_ID, port_id); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_get_mac_address_pf( __in efx_nic_t *enp, __out_ecount_opt(6) uint8_t mac_addrp[6]) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_MAC_ADDRESSES_IN_LEN, MC_CMD_GET_MAC_ADDRESSES_OUT_LEN)]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_MAC_ADDRESSES; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_MAC_ADDRESSES_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_MAC_ADDRESSES_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) { rc = EMSGSIZE; goto fail2; } if (MCDI_OUT_DWORD(req, GET_MAC_ADDRESSES_OUT_MAC_COUNT) < 1) { rc = ENOENT; goto fail3; } if (mac_addrp != NULL) { uint8_t *addrp; addrp = MCDI_OUT2(req, uint8_t, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE); EFX_MAC_ADDR_COPY(mac_addrp, addrp); } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_get_mac_address_vf( __in efx_nic_t *enp, __out_ecount_opt(6) uint8_t mac_addrp[6]) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN, MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX)]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_VPORT_GET_MAC_ADDRESSES; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMAX; MCDI_IN_SET_DWORD(req, VPORT_GET_MAC_ADDRESSES_IN_VPORT_ID, EVB_PORT_ID_ASSIGNED); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_VPORT_GET_MAC_ADDRESSES_OUT_LENMIN) { rc = EMSGSIZE; goto fail2; } if (MCDI_OUT_DWORD(req, VPORT_GET_MAC_ADDRESSES_OUT_MACADDR_COUNT) < 1) { rc = ENOENT; goto fail3; } if (mac_addrp != NULL) { uint8_t *addrp; addrp = MCDI_OUT2(req, uint8_t, VPORT_GET_MAC_ADDRESSES_OUT_MACADDR); EFX_MAC_ADDR_COPY(mac_addrp, addrp); } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_get_clock( __in efx_nic_t *enp, __out uint32_t *sys_freqp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_CLOCK_IN_LEN, MC_CMD_GET_CLOCK_OUT_LEN)]; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_CLOCK; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_CLOCK_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_CLOCK_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_CLOCK_OUT_LEN) { rc = EMSGSIZE; goto fail2; } *sys_freqp = MCDI_OUT_DWORD(req, GET_CLOCK_OUT_SYS_FREQ); if (*sys_freqp == 0) { rc = EINVAL; goto fail3; } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t efx_mcdi_get_vector_cfg( __in efx_nic_t *enp, __out_opt uint32_t *vec_basep, __out_opt uint32_t *pf_nvecp, __out_opt uint32_t *vf_nvecp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_VECTOR_CFG_IN_LEN, MC_CMD_GET_VECTOR_CFG_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_VECTOR_CFG; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_VECTOR_CFG_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_VECTOR_CFG_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_VECTOR_CFG_OUT_LEN) { rc = EMSGSIZE; goto fail2; } if (vec_basep != NULL) *vec_basep = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VEC_BASE); if (pf_nvecp != NULL) *pf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_PF); if (vf_nvecp != NULL) *vf_nvecp = MCDI_OUT_DWORD(req, GET_VECTOR_CFG_OUT_VECS_PER_VF); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_get_capabilities( __in efx_nic_t *enp, __out uint32_t *flagsp, __out uint32_t *flags2p) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN, MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_CAPABILITIES; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { rc = EMSGSIZE; goto fail2; } *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) *flags2p = 0; else *flags2p = MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_alloc_vis( __in efx_nic_t *enp, __in uint32_t min_vi_count, __in uint32_t max_vi_count, __out uint32_t *vi_basep, __out uint32_t *vi_countp, __out uint32_t *vi_shiftp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_ALLOC_VIS_IN_LEN, MC_CMD_ALLOC_VIS_OUT_LEN)]; efx_rc_t rc; if (vi_countp == NULL) { rc = EINVAL; goto fail1; } (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_ALLOC_VIS; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_ALLOC_VIS_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_ALLOC_VIS_OUT_LEN; MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MIN_VI_COUNT, min_vi_count); MCDI_IN_SET_DWORD(req, ALLOC_VIS_IN_MAX_VI_COUNT, max_vi_count); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail2; } if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_OUT_LEN) { rc = EMSGSIZE; goto fail3; } *vi_basep = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_BASE); *vi_countp = MCDI_OUT_DWORD(req, ALLOC_VIS_OUT_VI_COUNT); /* Report VI_SHIFT if available (always zero for Huntington) */ if (req.emr_out_length_used < MC_CMD_ALLOC_VIS_EXT_OUT_LEN) *vi_shiftp = 0; else *vi_shiftp = MCDI_OUT_DWORD(req, ALLOC_VIS_EXT_OUT_VI_SHIFT); return (0); 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_free_vis( __in efx_nic_t *enp) { efx_mcdi_req_t req; efx_rc_t rc; EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_IN_LEN == 0); EFX_STATIC_ASSERT(MC_CMD_FREE_VIS_OUT_LEN == 0); req.emr_cmd = MC_CMD_FREE_VIS; req.emr_in_buf = NULL; req.emr_in_length = 0; req.emr_out_buf = NULL; req.emr_out_length = 0; efx_mcdi_execute_quiet(enp, &req); /* Ignore ELREADY (no allocated VIs, so nothing to free) */ if ((req.emr_rc != 0) && (req.emr_rc != EALREADY)) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_alloc_piobuf( __in efx_nic_t *enp, __out efx_piobuf_handle_t *handlep) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_ALLOC_PIOBUF_IN_LEN, MC_CMD_ALLOC_PIOBUF_OUT_LEN)]; efx_rc_t rc; if (handlep == NULL) { rc = EINVAL; goto fail1; } (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_ALLOC_PIOBUF; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_ALLOC_PIOBUF_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_ALLOC_PIOBUF_OUT_LEN; efx_mcdi_execute_quiet(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail2; } if (req.emr_out_length_used < MC_CMD_ALLOC_PIOBUF_OUT_LEN) { rc = EMSGSIZE; goto fail3; } *handlep = MCDI_OUT_DWORD(req, ALLOC_PIOBUF_OUT_PIOBUF_HANDLE); return (0); 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_free_piobuf( __in efx_nic_t *enp, __in efx_piobuf_handle_t handle) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_FREE_PIOBUF_IN_LEN, MC_CMD_FREE_PIOBUF_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_FREE_PIOBUF; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_FREE_PIOBUF_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_FREE_PIOBUF_OUT_LEN; MCDI_IN_SET_DWORD(req, FREE_PIOBUF_IN_PIOBUF_HANDLE, handle); efx_mcdi_execute_quiet(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_link_piobuf( __in efx_nic_t *enp, __in uint32_t vi_index, __in efx_piobuf_handle_t handle) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_LINK_PIOBUF_IN_LEN, MC_CMD_LINK_PIOBUF_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_LINK_PIOBUF; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_LINK_PIOBUF_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_LINK_PIOBUF_OUT_LEN; MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_PIOBUF_HANDLE, handle); MCDI_IN_SET_DWORD(req, LINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t efx_mcdi_unlink_piobuf( __in efx_nic_t *enp, __in uint32_t vi_index) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_UNLINK_PIOBUF_IN_LEN, MC_CMD_UNLINK_PIOBUF_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_UNLINK_PIOBUF; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_UNLINK_PIOBUF_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_UNLINK_PIOBUF_OUT_LEN; MCDI_IN_SET_DWORD(req, UNLINK_PIOBUF_IN_TXQ_INSTANCE, vi_index); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static void ef10_nic_alloc_piobufs( __in efx_nic_t *enp, __in uint32_t max_piobuf_count) { efx_piobuf_handle_t *handlep; unsigned int i; efx_rc_t rc; EFSYS_ASSERT3U(max_piobuf_count, <=, EFX_ARRAY_SIZE(enp->en_arch.ef10.ena_piobuf_handle)); enp->en_arch.ef10.ena_piobuf_count = 0; for (i = 0; i < max_piobuf_count; i++) { handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; if ((rc = efx_mcdi_alloc_piobuf(enp, handlep)) != 0) goto fail1; enp->en_arch.ef10.ena_pio_alloc_map[i] = 0; enp->en_arch.ef10.ena_piobuf_count++; } return; fail1: for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; efx_mcdi_free_piobuf(enp, *handlep); *handlep = EFX_PIOBUF_HANDLE_INVALID; } enp->en_arch.ef10.ena_piobuf_count = 0; } static void ef10_nic_free_piobufs( __in efx_nic_t *enp) { efx_piobuf_handle_t *handlep; unsigned int i; for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { handlep = &enp->en_arch.ef10.ena_piobuf_handle[i]; efx_mcdi_free_piobuf(enp, *handlep); *handlep = EFX_PIOBUF_HANDLE_INVALID; } enp->en_arch.ef10.ena_piobuf_count = 0; } /* Sub-allocate a block from a piobuf */ __checkReturn efx_rc_t ef10_nic_pio_alloc( __inout efx_nic_t *enp, __out uint32_t *bufnump, __out efx_piobuf_handle_t *handlep, __out uint32_t *blknump, __out uint32_t *offsetp, __out size_t *sizep) { efx_nic_cfg_t *encp = &enp->en_nic_cfg; efx_drv_cfg_t *edcp = &enp->en_drv_cfg; uint32_t blk_per_buf; uint32_t buf, blk; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); EFSYS_ASSERT(bufnump); EFSYS_ASSERT(handlep); EFSYS_ASSERT(blknump); EFSYS_ASSERT(offsetp); EFSYS_ASSERT(sizep); if ((edcp->edc_pio_alloc_size == 0) || (enp->en_arch.ef10.ena_piobuf_count == 0)) { rc = ENOMEM; goto fail1; } blk_per_buf = encp->enc_piobuf_size / edcp->edc_pio_alloc_size; for (buf = 0; buf < enp->en_arch.ef10.ena_piobuf_count; buf++) { uint32_t *map = &enp->en_arch.ef10.ena_pio_alloc_map[buf]; if (~(*map) == 0) continue; EFSYS_ASSERT3U(blk_per_buf, <=, (8 * sizeof (*map))); for (blk = 0; blk < blk_per_buf; blk++) { if ((*map & (1u << blk)) == 0) { *map |= (1u << blk); goto done; } } } rc = ENOMEM; goto fail2; done: *handlep = enp->en_arch.ef10.ena_piobuf_handle[buf]; *bufnump = buf; *blknump = blk; *sizep = edcp->edc_pio_alloc_size; *offsetp = blk * (*sizep); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } /* Free a piobuf sub-allocated block */ __checkReturn efx_rc_t ef10_nic_pio_free( __inout efx_nic_t *enp, __in uint32_t bufnum, __in uint32_t blknum) { uint32_t *map; efx_rc_t rc; if ((bufnum >= enp->en_arch.ef10.ena_piobuf_count) || (blknum >= (8 * sizeof (*map)))) { rc = EINVAL; goto fail1; } map = &enp->en_arch.ef10.ena_pio_alloc_map[bufnum]; if ((*map & (1u << blknum)) == 0) { rc = ENOENT; goto fail2; } *map &= ~(1u << blknum); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_nic_pio_link( __inout efx_nic_t *enp, __in uint32_t vi_index, __in efx_piobuf_handle_t handle) { return (efx_mcdi_link_piobuf(enp, vi_index, handle)); } __checkReturn efx_rc_t ef10_nic_pio_unlink( __inout efx_nic_t *enp, __in uint32_t vi_index) { return (efx_mcdi_unlink_piobuf(enp, vi_index)); } __checkReturn efx_rc_t ef10_get_datapath_caps( __in efx_nic_t *enp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); uint32_t flags; uint32_t flags2; efx_rc_t rc; if ((rc = efx_mcdi_get_capabilities(enp, &flags, &flags2)) != 0) goto fail1; #define CAP_FLAG(flags1, field) \ ((flags1) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) #define CAP_FLAG2(flags2, field) \ ((flags2) & (1 << (MC_CMD_GET_CAPABILITIES_V2_OUT_ ## field ## _LBN))) /* * Huntington RXDP firmware inserts a 0 or 14 byte prefix. * We only support the 14 byte prefix here. */ if (CAP_FLAG(flags, RX_PREFIX_LEN_14) == 0) { rc = ENOTSUP; goto fail2; } encp->enc_rx_prefix_size = 14; /* Check if the firmware supports TSO */ encp->enc_fw_assisted_tso_enabled = CAP_FLAG(flags, TX_TSO) ? B_TRUE : B_FALSE; /* Check if the firmware supports FATSOv2 */ encp->enc_fw_assisted_tso_v2_enabled = CAP_FLAG2(flags2, TX_TSO_V2) ? B_TRUE : B_FALSE; /* Check if the firmware has vadapter/vport/vswitch support */ encp->enc_datapath_cap_evb = CAP_FLAG(flags, EVB) ? B_TRUE : B_FALSE; /* Check if the firmware supports VLAN insertion */ encp->enc_hw_tx_insert_vlan_enabled = CAP_FLAG(flags, TX_VLAN_INSERTION) ? B_TRUE : B_FALSE; /* Check if the firmware supports RX event batching */ encp->enc_rx_batching_enabled = CAP_FLAG(flags, RX_BATCHING) ? B_TRUE : B_FALSE; if (encp->enc_rx_batching_enabled) encp->enc_rx_batch_max = 16; /* Check if the firmware supports disabling scatter on RXQs */ encp->enc_rx_disable_scatter_supported = CAP_FLAG(flags, RX_DISABLE_SCATTER) ? B_TRUE : B_FALSE; /* Check if the firmware supports set mac with running filters */ encp->enc_allow_set_mac_with_installed_filters = CAP_FLAG(flags, VADAPTOR_PERMIT_SET_MAC_WHEN_FILTERS_INSTALLED) ? B_TRUE : B_FALSE; /* * Check if firmware supports the extended MC_CMD_SET_MAC, which allows * specifying which parameters to configure. */ encp->enc_enhanced_set_mac_supported = CAP_FLAG(flags, SET_MAC_ENHANCED) ? B_TRUE : B_FALSE; #undef CAP_FLAG #undef CAP_FLAG2 return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_get_privilege_mask( __in efx_nic_t *enp, __out uint32_t *maskp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); uint32_t mask; efx_rc_t rc; if ((rc = efx_mcdi_privilege_mask(enp, encp->enc_pf, encp->enc_vf, &mask)) != 0) { if (rc != ENOTSUP) goto fail1; /* Fallback for old firmware without privilege mask support */ if (EFX_PCI_FUNCTION_IS_PF(encp)) { /* Assume PF has admin privilege */ mask = EF10_LEGACY_PF_PRIVILEGE_MASK; } else { /* VF is always unprivileged by default */ mask = EF10_LEGACY_VF_PRIVILEGE_MASK; } } *maskp = mask; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } /* * The external port mapping is a one-based numbering of the external * connectors on the board. It does not distinguish off-board separated * outputs such as multi-headed cables. * The number of ports that map to each external port connector * on the board is determined by the chip family and the port modes to * which the NIC can be configured. The mapping table lists modes with * port numbering requirements in increasing order. */ static struct { efx_family_t family; uint32_t modes_mask; uint32_t stride; } __ef10_external_port_mappings[] = { /* Supported modes requiring 1 output per port */ { EFX_FAMILY_HUNTINGTON, (1 << TLV_PORT_MODE_10G) | (1 << TLV_PORT_MODE_10G_10G) | (1 << TLV_PORT_MODE_10G_10G_10G_10G), 1 }, { EFX_FAMILY_MEDFORD, (1 << TLV_PORT_MODE_10G) | (1 << TLV_PORT_MODE_10G_10G) | (1 << TLV_PORT_MODE_10G_10G_10G_10G), 1 }, /* Supported modes requiring 2 outputs per port */ { EFX_FAMILY_HUNTINGTON, (1 << TLV_PORT_MODE_40G) | (1 << TLV_PORT_MODE_40G_40G) | (1 << TLV_PORT_MODE_40G_10G_10G) | (1 << TLV_PORT_MODE_10G_10G_40G), 2 }, { EFX_FAMILY_MEDFORD, (1 << TLV_PORT_MODE_40G) | (1 << TLV_PORT_MODE_40G_40G) | (1 << TLV_PORT_MODE_40G_10G_10G) | (1 << TLV_PORT_MODE_10G_10G_40G), 2 }, /* Supported modes requiring 4 outputs per port */ { EFX_FAMILY_MEDFORD, (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q) | (1 << TLV_PORT_MODE_10G_10G_10G_10G_Q2), 4 }, }; __checkReturn efx_rc_t ef10_external_port_mapping( __in efx_nic_t *enp, __in uint32_t port, __out uint8_t *external_portp) { efx_rc_t rc; int i; uint32_t port_modes; uint32_t matches; uint32_t stride = 1; /* default 1-1 mapping */ if ((rc = efx_mcdi_get_port_modes(enp, &port_modes)) != 0) { /* No port mode information available - use default mapping */ goto out; } /* * Infer the internal port -> external port mapping from * the possible port modes for this NIC. */ for (i = 0; i < EFX_ARRAY_SIZE(__ef10_external_port_mappings); ++i) { if (__ef10_external_port_mappings[i].family != enp->en_family) continue; matches = (__ef10_external_port_mappings[i].modes_mask & port_modes); if (matches != 0) { stride = __ef10_external_port_mappings[i].stride; port_modes &= ~matches; } } if (port_modes != 0) { /* Some advertised modes are not supported */ rc = ENOTSUP; goto fail1; } out: /* * Scale as required by last matched mode and then convert to * one-based numbering */ *external_portp = (uint8_t)(port / stride) + 1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t hunt_board_cfg( __in efx_nic_t *enp) { efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); efx_nic_cfg_t *encp = &(enp->en_nic_cfg); uint8_t mac_addr[6]; uint32_t board_type = 0; ef10_link_state_t els; efx_port_t *epp = &(enp->en_port); uint32_t port; uint32_t pf; uint32_t vf; uint32_t mask; uint32_t flags; uint32_t sysclk; uint32_t base, nvec; efx_rc_t rc; if ((rc = efx_mcdi_get_port_assignment(enp, &port)) != 0) goto fail1; /* * NOTE: The MCDI protocol numbers ports from zero. * The common code MCDI interface numbers ports from one. */ emip->emi_port = port + 1; if ((rc = ef10_external_port_mapping(enp, port, &encp->enc_external_port)) != 0) goto fail2; /* * Get PCIe function number from firmware (used for * per-function privilege and dynamic config info). * - PCIe PF: pf = PF number, vf = 0xffff. * - PCIe VF: pf = parent PF, vf = VF number. */ if ((rc = efx_mcdi_get_function_info(enp, &pf, &vf)) != 0) goto fail3; encp->enc_pf = pf; encp->enc_vf = vf; /* MAC address for this function */ if (EFX_PCI_FUNCTION_IS_PF(encp)) { rc = efx_mcdi_get_mac_address_pf(enp, mac_addr); if ((rc == 0) && (mac_addr[0] & 0x02)) { /* * If the static config does not include a global MAC * address pool then the board may return a locally * administered MAC address (this should only happen on * incorrectly programmed boards). */ rc = EINVAL; } } else { rc = efx_mcdi_get_mac_address_vf(enp, mac_addr); } if (rc != 0) goto fail4; EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr); /* Board configuration */ rc = efx_mcdi_get_board_cfg(enp, &board_type, NULL, NULL); if (rc != 0) { /* Unprivileged functions may not be able to read board cfg */ if (rc == EACCES) board_type = 0; else goto fail5; } encp->enc_board_type = board_type; encp->enc_clk_mult = 1; /* not used for Huntington */ /* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */ if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0) goto fail6; /* Obtain the default PHY advertised capabilities */ if ((rc = ef10_phy_get_link(enp, &els)) != 0) goto fail7; epp->ep_default_adv_cap_mask = els.els_adv_cap_mask; epp->ep_adv_cap_mask = els.els_adv_cap_mask; /* * Enable firmware workarounds for hardware errata. * Expected responses are: * - 0 (zero): * Success: workaround enabled or disabled as requested. * - MC_CMD_ERR_ENOSYS (reported as ENOTSUP): * Firmware does not support the MC_CMD_WORKAROUND request. * (assume that the workaround is not supported). * - MC_CMD_ERR_ENOENT (reported as ENOENT): * Firmware does not support the requested workaround. * - MC_CMD_ERR_EPERM (reported as EACCES): * Unprivileged function cannot enable/disable workarounds. * * See efx_mcdi_request_errcode() for MCDI error translations. */ /* * If the bug35388 workaround is enabled, then use an indirect access * method to avoid unsafe EVQ writes. */ rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG35388, B_TRUE, NULL); if ((rc == 0) || (rc == EACCES)) encp->enc_bug35388_workaround = B_TRUE; else if ((rc == ENOTSUP) || (rc == ENOENT)) encp->enc_bug35388_workaround = B_FALSE; else goto fail8; /* * If the bug41750 workaround is enabled, then do not test interrupts, * as the test will fail (seen with Greenport controllers). */ rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG41750, B_TRUE, NULL); if (rc == 0) { encp->enc_bug41750_workaround = B_TRUE; } else if (rc == EACCES) { /* Assume a controller with 40G ports needs the workaround. */ if (epp->ep_default_adv_cap_mask & EFX_PHY_CAP_40000FDX) encp->enc_bug41750_workaround = B_TRUE; else encp->enc_bug41750_workaround = B_FALSE; } else if ((rc == ENOTSUP) || (rc == ENOENT)) { encp->enc_bug41750_workaround = B_FALSE; } else { goto fail9; } if (EFX_PCI_FUNCTION_IS_VF(encp)) { /* Interrupt testing does not work for VFs. See bug50084. */ encp->enc_bug41750_workaround = B_TRUE; } /* * If the bug26807 workaround is enabled, then firmware has enabled * support for chained multicast filters. Firmware will reset (FLR) * functions which have filters in the hardware filter table when the * workaround is enabled/disabled. * * We must recheck if the workaround is enabled after inserting the * first hardware filter, in case it has been changed since this check. */ rc = efx_mcdi_set_workaround(enp, MC_CMD_WORKAROUND_BUG26807, B_TRUE, &flags); if (rc == 0) { encp->enc_bug26807_workaround = B_TRUE; if (flags & (1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN)) { /* * Other functions had installed filters before the * workaround was enabled, and they have been reset * by firmware. */ EFSYS_PROBE(bug26807_workaround_flr_done); /* FIXME: bump MC warm boot count ? */ } } else if (rc == EACCES) { /* * Unprivileged functions cannot enable the workaround in older * firmware. */ encp->enc_bug26807_workaround = B_FALSE; } else if ((rc == ENOTSUP) || (rc == ENOENT)) { encp->enc_bug26807_workaround = B_FALSE; } else { goto fail10; } /* Get sysclk frequency (in MHz). */ if ((rc = efx_mcdi_get_clock(enp, &sysclk)) != 0) goto fail11; /* * The timer quantum is 1536 sysclk cycles, documented for the * EV_TMR_VAL field of EV_TIMER_TBL. Scale for MHz and ns units. */ encp->enc_evq_timer_quantum_ns = 1536000UL / sysclk; /* 1536 cycles */ if (encp->enc_bug35388_workaround) { encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << ERF_DD_EVQ_IND_TIMER_VAL_WIDTH) / 1000; } else { encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000; } /* Check capabilities of running datapath firmware */ if ((rc = ef10_get_datapath_caps(enp)) != 0) goto fail12; /* Alignment for receive packet DMA buffers */ encp->enc_rx_buf_align_start = 1; encp->enc_rx_buf_align_end = 64; /* RX DMA end padding */ /* Alignment for WPTR updates */ encp->enc_rx_push_align = EF10_RX_WPTR_ALIGN; /* * Set resource limits for MC_CMD_ALLOC_VIS. Note that we cannot use * MC_CMD_GET_RESOURCE_LIMITS here as that reports the available * resources (allocated to this PCIe function), which is zero until * after we have allocated VIs. */ encp->enc_evq_limit = 1024; encp->enc_rxq_limit = EFX_RXQ_LIMIT_TARGET; encp->enc_txq_limit = EFX_TXQ_LIMIT_TARGET; encp->enc_buftbl_limit = 0xFFFFFFFF; encp->enc_piobuf_limit = HUNT_PIOBUF_NBUFS; encp->enc_piobuf_size = HUNT_PIOBUF_SIZE; encp->enc_piobuf_min_alloc_size = HUNT_MIN_PIO_ALLOC_SIZE; /* * Get the current privilege mask. Note that this may be modified * dynamically, so this value is informational only. DO NOT use * the privilege mask to check for sufficient privileges, as that * can result in time-of-check/time-of-use bugs. */ if ((rc = ef10_get_privilege_mask(enp, &mask)) != 0) goto fail13; encp->enc_privilege_mask = mask; /* Get interrupt vector limits */ if ((rc = efx_mcdi_get_vector_cfg(enp, &base, &nvec, NULL)) != 0) { if (EFX_PCI_FUNCTION_IS_PF(encp)) goto fail14; /* Ignore error (cannot query vector limits from a VF). */ base = 0; nvec = 1024; } encp->enc_intr_vec_base = base; encp->enc_intr_limit = nvec; /* * Maximum number of bytes into the frame the TCP header can start for * firmware assisted TSO to work. */ encp->enc_tx_tso_tcp_header_offset_limit = EF10_TCP_HEADER_OFFSET_LIMIT; return (0); fail14: EFSYS_PROBE(fail14); fail13: EFSYS_PROBE(fail13); fail12: EFSYS_PROBE(fail12); fail11: EFSYS_PROBE(fail11); fail10: EFSYS_PROBE(fail10); fail9: EFSYS_PROBE(fail9); fail8: EFSYS_PROBE(fail8); fail7: EFSYS_PROBE(fail7); fail6: EFSYS_PROBE(fail6); 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 ef10_nic_probe( __in efx_nic_t *enp) { - efx_nic_ops_t *enop = enp->en_enop; + const efx_nic_ops_t *enop = enp->en_enop; efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); /* Read and clear any assertion state */ if ((rc = efx_mcdi_read_assertion(enp)) != 0) goto fail1; /* Exit the assertion handler */ if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) if (rc != EACCES) goto fail2; if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) goto fail3; if ((rc = enop->eno_board_cfg(enp)) != 0) if (rc != EACCES) goto fail4; /* * Set default driver config limits (based on board config). * * FIXME: For now allocate a fixed number of VIs which is likely to be * sufficient and small enough to allow multiple functions on the same * port. */ edcp->edc_min_vi_count = edcp->edc_max_vi_count = MIN(128, MAX(encp->enc_rxq_limit, encp->enc_txq_limit)); /* The client driver must configure and enable PIO buffer support */ edcp->edc_max_piobuf_count = 0; edcp->edc_pio_alloc_size = 0; #if EFSYS_OPT_MAC_STATS /* Wipe the MAC statistics */ if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) goto fail5; #endif #if EFSYS_OPT_LOOPBACK if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) goto fail6; #endif #if EFSYS_OPT_MON_STATS if ((rc = mcdi_mon_cfg_build(enp)) != 0) { /* Unprivileged functions do not have access to sensors */ if (rc != EACCES) goto fail7; } #endif encp->enc_features = enp->en_features; return (0); #if EFSYS_OPT_MON_STATS fail7: EFSYS_PROBE(fail7); #endif #if EFSYS_OPT_LOOPBACK fail6: EFSYS_PROBE(fail6); #endif #if EFSYS_OPT_MAC_STATS fail5: EFSYS_PROBE(fail5); #endif 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 ef10_nic_set_drv_limits( __inout efx_nic_t *enp, __in efx_drv_limits_t *edlp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); uint32_t min_evq_count, max_evq_count; uint32_t min_rxq_count, max_rxq_count; uint32_t min_txq_count, max_txq_count; efx_rc_t rc; if (edlp == NULL) { rc = EINVAL; goto fail1; } /* Get minimum required and maximum usable VI limits */ min_evq_count = MIN(edlp->edl_min_evq_count, encp->enc_evq_limit); min_rxq_count = MIN(edlp->edl_min_rxq_count, encp->enc_rxq_limit); min_txq_count = MIN(edlp->edl_min_txq_count, encp->enc_txq_limit); edcp->edc_min_vi_count = MAX(min_evq_count, MAX(min_rxq_count, min_txq_count)); max_evq_count = MIN(edlp->edl_max_evq_count, encp->enc_evq_limit); max_rxq_count = MIN(edlp->edl_max_rxq_count, encp->enc_rxq_limit); max_txq_count = MIN(edlp->edl_max_txq_count, encp->enc_txq_limit); edcp->edc_max_vi_count = MAX(max_evq_count, MAX(max_rxq_count, max_txq_count)); /* * Check limits for sub-allocated piobuf blocks. * PIO is optional, so don't fail if the limits are incorrect. */ if ((encp->enc_piobuf_size == 0) || (encp->enc_piobuf_limit == 0) || (edlp->edl_min_pio_alloc_size == 0) || (edlp->edl_min_pio_alloc_size > encp->enc_piobuf_size)) { /* Disable PIO */ edcp->edc_max_piobuf_count = 0; edcp->edc_pio_alloc_size = 0; } else { uint32_t blk_size, blk_count, blks_per_piobuf; blk_size = MAX(edlp->edl_min_pio_alloc_size, encp->enc_piobuf_min_alloc_size); blks_per_piobuf = encp->enc_piobuf_size / blk_size; EFSYS_ASSERT3U(blks_per_piobuf, <=, 32); blk_count = (encp->enc_piobuf_limit * blks_per_piobuf); /* A zero max pio alloc count means unlimited */ if ((edlp->edl_max_pio_alloc_count > 0) && (edlp->edl_max_pio_alloc_count < blk_count)) { blk_count = edlp->edl_max_pio_alloc_count; } edcp->edc_pio_alloc_size = blk_size; edcp->edc_max_piobuf_count = (blk_count + (blks_per_piobuf - 1)) / blks_per_piobuf; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_nic_reset( __in efx_nic_t *enp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_ENTITY_RESET_IN_LEN, MC_CMD_ENTITY_RESET_OUT_LEN)]; efx_rc_t rc; /* ef10_nic_reset() is called to recover from BADASSERT failures. */ if ((rc = efx_mcdi_read_assertion(enp)) != 0) goto fail1; if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) goto fail2; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_ENTITY_RESET; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_ENTITY_RESET_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_ENTITY_RESET_OUT_LEN; MCDI_IN_POPULATE_DWORD_1(req, ENTITY_RESET_IN_FLAG, ENTITY_RESET_IN_FUNCTION_RESOURCE_RESET, 1); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail3; } /* Clear RX/TX DMA queue errors */ enp->en_reset_flags &= ~(EFX_RESET_RXQ_ERR | EFX_RESET_TXQ_ERR); return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_nic_init( __in efx_nic_t *enp) { efx_drv_cfg_t *edcp = &(enp->en_drv_cfg); uint32_t min_vi_count, max_vi_count; uint32_t vi_count, vi_base, vi_shift; uint32_t i; uint32_t retry; uint32_t delay_us; efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); /* Enable reporting of some events (e.g. link change) */ if ((rc = efx_mcdi_log_ctrl(enp)) != 0) goto fail1; /* Allocate (optional) on-chip PIO buffers */ ef10_nic_alloc_piobufs(enp, edcp->edc_max_piobuf_count); /* * For best performance, PIO writes should use a write-combined * (WC) memory mapping. Using a separate WC mapping for the PIO * aperture of each VI would be a burden to drivers (and not * possible if the host page size is >4Kbyte). * * To avoid this we use a single uncached (UC) mapping for VI * register access, and a single WC mapping for extra VIs used * for PIO writes. * * Each piobuf must be linked to a VI in the WC mapping, and to * each VI that is using a sub-allocated block from the piobuf. */ min_vi_count = edcp->edc_min_vi_count; max_vi_count = edcp->edc_max_vi_count + enp->en_arch.ef10.ena_piobuf_count; /* Ensure that the previously attached driver's VIs are freed */ if ((rc = efx_mcdi_free_vis(enp)) != 0) goto fail2; /* * Reserve VI resources (EVQ+RXQ+TXQ) for this PCIe function. If this * fails then retrying the request for fewer VI resources may succeed. */ vi_count = 0; if ((rc = efx_mcdi_alloc_vis(enp, min_vi_count, max_vi_count, &vi_base, &vi_count, &vi_shift)) != 0) goto fail3; EFSYS_PROBE2(vi_alloc, uint32_t, vi_base, uint32_t, vi_count); if (vi_count < min_vi_count) { rc = ENOMEM; goto fail4; } enp->en_arch.ef10.ena_vi_base = vi_base; enp->en_arch.ef10.ena_vi_count = vi_count; enp->en_arch.ef10.ena_vi_shift = vi_shift; if (vi_count < min_vi_count + enp->en_arch.ef10.ena_piobuf_count) { /* Not enough extra VIs to map piobufs */ ef10_nic_free_piobufs(enp); } enp->en_arch.ef10.ena_pio_write_vi_base = vi_count - enp->en_arch.ef10.ena_piobuf_count; /* Save UC memory mapping details */ enp->en_arch.ef10.ena_uc_mem_map_offset = 0; if (enp->en_arch.ef10.ena_piobuf_count > 0) { enp->en_arch.ef10.ena_uc_mem_map_size = (ER_DZ_TX_PIOBUF_STEP * enp->en_arch.ef10.ena_pio_write_vi_base); } else { enp->en_arch.ef10.ena_uc_mem_map_size = (ER_DZ_TX_PIOBUF_STEP * enp->en_arch.ef10.ena_vi_count); } /* Save WC memory mapping details */ enp->en_arch.ef10.ena_wc_mem_map_offset = enp->en_arch.ef10.ena_uc_mem_map_offset + enp->en_arch.ef10.ena_uc_mem_map_size; enp->en_arch.ef10.ena_wc_mem_map_size = (ER_DZ_TX_PIOBUF_STEP * enp->en_arch.ef10.ena_piobuf_count); /* Link piobufs to extra VIs in WC mapping */ if (enp->en_arch.ef10.ena_piobuf_count > 0) { for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { rc = efx_mcdi_link_piobuf(enp, enp->en_arch.ef10.ena_pio_write_vi_base + i, enp->en_arch.ef10.ena_piobuf_handle[i]); if (rc != 0) break; } } /* * Allocate a vAdaptor attached to our upstream vPort/pPort. * * On a VF, this may fail with MC_CMD_ERR_NO_EVB_PORT (ENOENT) if the PF * driver has yet to bring up the EVB port. See bug 56147. In this case, * retry the request several times after waiting a while. The wait time * between retries starts small (10ms) and exponentially increases. * Total wait time is a little over two seconds. Retry logic in the * client driver may mean this whole loop is repeated if it continues to * fail. */ retry = 0; delay_us = 10000; while ((rc = efx_mcdi_vadaptor_alloc(enp, EVB_PORT_ID_ASSIGNED)) != 0) { if (EFX_PCI_FUNCTION_IS_PF(&enp->en_nic_cfg) || (rc != ENOENT)) { /* * Do not retry alloc for PF, or for other errors on * a VF. */ goto fail5; } /* VF startup before PF is ready. Retry allocation. */ if (retry > 5) { /* Too many attempts */ rc = EINVAL; goto fail6; } EFSYS_PROBE1(mcdi_no_evb_port_retry, int, retry); EFSYS_SLEEP(delay_us); retry++; if (delay_us < 500000) delay_us <<= 2; } enp->en_vport_id = EVB_PORT_ID_ASSIGNED; enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V2; return (0); fail6: EFSYS_PROBE(fail6); fail5: EFSYS_PROBE(fail5); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); ef10_nic_free_piobufs(enp); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_nic_get_vi_pool( __in efx_nic_t *enp, __out uint32_t *vi_countp) { EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); /* * Report VIs that the client driver can use. * Do not include VIs used for PIO buffer writes. */ *vi_countp = enp->en_arch.ef10.ena_pio_write_vi_base; return (0); } __checkReturn efx_rc_t ef10_nic_get_bar_region( __in efx_nic_t *enp, __in efx_nic_region_t region, __out uint32_t *offsetp, __out size_t *sizep) { efx_rc_t rc; EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || enp->en_family == EFX_FAMILY_MEDFORD); /* * TODO: Specify host memory mapping alignment and granularity * in efx_drv_limits_t so that they can be taken into account * when allocating extra VIs for PIO writes. */ switch (region) { case EFX_REGION_VI: /* UC mapped memory BAR region for VI registers */ *offsetp = enp->en_arch.ef10.ena_uc_mem_map_offset; *sizep = enp->en_arch.ef10.ena_uc_mem_map_size; break; case EFX_REGION_PIO_WRITE_VI: /* WC mapped memory BAR region for piobuf writes */ *offsetp = enp->en_arch.ef10.ena_wc_mem_map_offset; *sizep = enp->en_arch.ef10.ena_wc_mem_map_size; break; default: rc = EINVAL; goto fail1; } return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void ef10_nic_fini( __in efx_nic_t *enp) { uint32_t i; efx_rc_t rc; (void) efx_mcdi_vadaptor_free(enp, enp->en_vport_id); enp->en_vport_id = 0; /* Unlink piobufs from extra VIs in WC mapping */ if (enp->en_arch.ef10.ena_piobuf_count > 0) { for (i = 0; i < enp->en_arch.ef10.ena_piobuf_count; i++) { rc = efx_mcdi_unlink_piobuf(enp, enp->en_arch.ef10.ena_pio_write_vi_base + i); if (rc != 0) break; } } ef10_nic_free_piobufs(enp); (void) efx_mcdi_free_vis(enp); enp->en_arch.ef10.ena_vi_count = 0; } void ef10_nic_unprobe( __in efx_nic_t *enp) { #if EFSYS_OPT_MON_STATS mcdi_mon_cfg_free(enp); #endif /* EFSYS_OPT_MON_STATS */ (void) efx_mcdi_drv_attach(enp, B_FALSE); } #if EFSYS_OPT_DIAG __checkReturn efx_rc_t ef10_nic_register_test( __in efx_nic_t *enp) { efx_rc_t rc; /* FIXME */ _NOTE(ARGUNUSED(enp)) if (B_FALSE) { rc = ENOTSUP; goto fail1; } /* FIXME */ return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_DIAG */ #endif /* EFSYS_OPT_HUNTINGTON */ Index: head/sys/dev/sfxge/common/siena_mac.c =================================================================== --- head/sys/dev/sfxge/common/siena_mac.c (revision 299516) +++ head/sys/dev/sfxge/common/siena_mac.c (revision 299517) @@ -1,435 +1,435 @@ /*- * Copyright (c) 2009-2015 Solarflare Communications Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_SIENA __checkReturn efx_rc_t siena_mac_poll( __in efx_nic_t *enp, __out efx_link_mode_t *link_modep) { efx_port_t *epp = &(enp->en_port); siena_link_state_t sls; efx_rc_t rc; if ((rc = siena_phy_get_link(enp, &sls)) != 0) goto fail1; epp->ep_adv_cap_mask = sls.sls_adv_cap_mask; epp->ep_fcntl = sls.sls_fcntl; *link_modep = sls.sls_link_mode; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); *link_modep = EFX_LINK_UNKNOWN; return (rc); } __checkReturn efx_rc_t siena_mac_up( __in efx_nic_t *enp, __out boolean_t *mac_upp) { siena_link_state_t sls; efx_rc_t rc; /* * Because Siena doesn't *require* polling, we can't rely on * siena_mac_poll() being executed to populate epp->ep_mac_up. */ if ((rc = siena_phy_get_link(enp, &sls)) != 0) goto fail1; *mac_upp = sls.sls_mac_up; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t siena_mac_reconfigure( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_oword_t multicast_hash[2]; efx_mcdi_req_t req; uint8_t payload[MAX(MAX(MC_CMD_SET_MAC_IN_LEN, MC_CMD_SET_MAC_OUT_LEN), MAX(MC_CMD_SET_MCAST_HASH_IN_LEN, MC_CMD_SET_MCAST_HASH_OUT_LEN))]; unsigned int fcntl; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_SET_MAC; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_SET_MAC_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_SET_MAC_OUT_LEN; MCDI_IN_SET_DWORD(req, SET_MAC_IN_MTU, epp->ep_mac_pdu); MCDI_IN_SET_DWORD(req, SET_MAC_IN_DRAIN, epp->ep_mac_drain ? 1 : 0); EFX_MAC_ADDR_COPY(MCDI_IN2(req, uint8_t, SET_MAC_IN_ADDR), epp->ep_mac_addr); MCDI_IN_POPULATE_DWORD_2(req, SET_MAC_IN_REJECT, SET_MAC_IN_REJECT_UNCST, !epp->ep_all_unicst, SET_MAC_IN_REJECT_BRDCST, !epp->ep_brdcst); if (epp->ep_fcntl_autoneg) /* efx_fcntl_set() has already set the phy capabilities */ fcntl = MC_CMD_FCNTL_AUTO; else if (epp->ep_fcntl & EFX_FCNTL_RESPOND) fcntl = (epp->ep_fcntl & EFX_FCNTL_GENERATE) ? MC_CMD_FCNTL_BIDIR : MC_CMD_FCNTL_RESPOND; else fcntl = MC_CMD_FCNTL_OFF; MCDI_IN_SET_DWORD(req, SET_MAC_IN_FCNTL, fcntl); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } /* Push multicast hash */ if (epp->ep_all_mulcst) { /* A hash matching all multicast is all 1s */ EFX_SET_OWORD(multicast_hash[0]); EFX_SET_OWORD(multicast_hash[1]); } else if (epp->ep_mulcst) { /* Use the hash set by the multicast list */ multicast_hash[0] = epp->ep_multicst_hash[0]; multicast_hash[1] = epp->ep_multicst_hash[1]; } else { /* A hash matching no traffic is simply 0 */ EFX_ZERO_OWORD(multicast_hash[0]); EFX_ZERO_OWORD(multicast_hash[1]); } /* * Broadcast packets go through the multicast hash filter. * The IEEE 802.3 CRC32 of the broadcast address is 0xbe2612ff * so we always add bit 0xff to the mask (bit 0x7f in the * second octword). */ if (epp->ep_brdcst) EFX_SET_OWORD_BIT(multicast_hash[1], 0x7f); (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_SET_MCAST_HASH; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_SET_MCAST_HASH_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_SET_MCAST_HASH_OUT_LEN; memcpy(MCDI_IN2(req, uint8_t, SET_MCAST_HASH_IN_HASH0), multicast_hash, sizeof (multicast_hash)); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #if EFSYS_OPT_LOOPBACK __checkReturn efx_rc_t siena_mac_loopback_set( __in efx_nic_t *enp, __in efx_link_mode_t link_mode, __in efx_loopback_type_t loopback_type) { efx_port_t *epp = &(enp->en_port); - efx_phy_ops_t *epop = epp->ep_epop; + const efx_phy_ops_t *epop = epp->ep_epop; efx_loopback_type_t old_loopback_type; efx_link_mode_t old_loopback_link_mode; efx_rc_t rc; /* The PHY object handles this on Siena */ old_loopback_type = epp->ep_loopback_type; old_loopback_link_mode = epp->ep_loopback_link_mode; epp->ep_loopback_type = loopback_type; epp->ep_loopback_link_mode = link_mode; if ((rc = epop->epo_reconfigure(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE(fail2); epp->ep_loopback_type = old_loopback_type; epp->ep_loopback_link_mode = old_loopback_link_mode; return (rc); } #endif /* EFSYS_OPT_LOOPBACK */ #if EFSYS_OPT_MAC_STATS #define SIENA_MAC_STAT_READ(_esmp, _field, _eqp) \ EFSYS_MEM_READQ((_esmp), (_field) * sizeof (efx_qword_t), _eqp) __checkReturn efx_rc_t siena_mac_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_MAC_NSTATS) efsys_stat_t *stat, __inout_opt uint32_t *generationp) { efx_qword_t value; efx_qword_t generation_start; efx_qword_t generation_end; _NOTE(ARGUNUSED(enp)) /* Read END first so we don't race with the MC */ EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_END, &generation_end); EFSYS_MEM_READ_BARRIER(); /* TX */ SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_CONTROL_PKTS, &value); EFSYS_STAT_SUBR_QWORD(&(stat[EFX_MAC_TX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_PAUSE_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_PAUSE_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_UNICAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_UNICST_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTICAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULTICST_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BROADCAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_BRDCST_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_OCTETS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LT64_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_64_PKTS, &value); EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_TX_LE_64_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_65_TO_127_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_65_TO_127_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_128_TO_255_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_128_TO_255_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_256_TO_511_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_256_TO_511_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_512_TO_1023_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_512_TO_1023_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_1024_TO_15XX_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_1024_TO_15XX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_15XX_TO_JUMBO_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_GTJUMBO_PKTS, &value); EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_TX_GE_15XX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_BAD_FCS_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_ERRORS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_SINGLE_COLLISION_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_SGL_COL_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_MULTIPLE_COLLISION_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_MULT_COL_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_COLLISION_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_COL_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_LATE_COLLISION_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_LATE_COL_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_DEFERRED_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_DEF_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_TX_EXCESSIVE_DEFERRED_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_TX_EX_DEF_PKTS]), &value); /* RX */ SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BYTES, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_OCTETS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNICAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_UNICST_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MULTICAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MULTICST_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BROADCAST_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_BRDCST_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_PAUSE_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_PAUSE_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_UNDERSIZE_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_64_PKTS, &value); EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_LE_64_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_65_TO_127_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_65_TO_127_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_128_TO_255_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_128_TO_255_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_256_TO_511_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_256_TO_511_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_512_TO_1023_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_512_TO_1023_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_1024_TO_15XX_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_1024_TO_15XX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_15XX_TO_JUMBO_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_GTJUMBO_PKTS, &value); EFSYS_STAT_INCR_QWORD(&(stat[EFX_MAC_RX_GE_15XX_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_BAD_FCS_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FCS_ERRORS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_OVERFLOW_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_DROP_EVENTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_FALSE_CARRIER_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_FALSE_CARRIER_ERRORS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_SYMBOL_ERROR_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_SYMBOL_ERRORS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_ALIGN_ERROR_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_ALIGN_ERRORS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_INTERNAL_ERROR_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_INTERNAL_ERRORS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_JABBER_PKTS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_JABBER_PKTS]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_CHAR_ERR, &value); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_CHAR_ERR]), &(value.eq_dword[0])); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_CHAR_ERR]), &(value.eq_dword[1])); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_CHAR_ERR, &value); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_CHAR_ERR]), &(value.eq_dword[0])); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_CHAR_ERR]), &(value.eq_dword[1])); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES01_DISP_ERR, &value); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE0_DISP_ERR]), &(value.eq_dword[0])); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE1_DISP_ERR]), &(value.eq_dword[1])); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_LANES23_DISP_ERR, &value); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE2_DISP_ERR]), &(value.eq_dword[0])); EFSYS_STAT_SET_DWORD(&(stat[EFX_MAC_RX_LANE3_DISP_ERR]), &(value.eq_dword[1])); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_MATCH_FAULT, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_MATCH_FAULT]), &value); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_RX_NODESC_DROPS, &value); EFSYS_STAT_SET_QWORD(&(stat[EFX_MAC_RX_NODESC_DROP_CNT]), &value); EFSYS_DMA_SYNC_FOR_KERNEL(esmp, 0, EFX_MAC_STATS_SIZE); EFSYS_MEM_READ_BARRIER(); SIENA_MAC_STAT_READ(esmp, MC_CMD_MAC_GENERATION_START, &generation_start); /* Check that we didn't read the stats in the middle of a DMA */ /* Not a good enough check ? */ if (memcmp(&generation_start, &generation_end, sizeof (generation_start))) return (EAGAIN); if (generationp) *generationp = EFX_QWORD_FIELD(generation_start, EFX_DWORD_0); return (0); } #endif /* EFSYS_OPT_MAC_STATS */ #endif /* EFSYS_OPT_SIENA */