15e111ed8SAndrew Rybchenko /* SPDX-License-Identifier: BSD-3-Clause 25e111ed8SAndrew Rybchenko * 35e111ed8SAndrew Rybchenko * Copyright(c) 2019-2020 Xilinx, Inc. 45e111ed8SAndrew Rybchenko * Copyright(c) 2007-2019 Solarflare Communications Inc. 55e111ed8SAndrew Rybchenko */ 65e111ed8SAndrew Rybchenko 75e111ed8SAndrew Rybchenko #include "efx.h" 85e111ed8SAndrew Rybchenko #include "efx_impl.h" 95e111ed8SAndrew Rybchenko #if EFSYS_OPT_MON_MCDI 105e111ed8SAndrew Rybchenko #include "mcdi_mon.h" 115e111ed8SAndrew Rybchenko #endif 125e111ed8SAndrew Rybchenko 135e111ed8SAndrew Rybchenko #define EFX_EV_PRESENT(_qword) \ 145e111ed8SAndrew Rybchenko (EFX_QWORD_FIELD((_qword), EFX_DWORD_0) != 0xffffffff && \ 155e111ed8SAndrew Rybchenko EFX_QWORD_FIELD((_qword), EFX_DWORD_1) != 0xffffffff) 165e111ed8SAndrew Rybchenko 175e111ed8SAndrew Rybchenko 185e111ed8SAndrew Rybchenko 195e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA 205e111ed8SAndrew Rybchenko 215e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 225e111ed8SAndrew Rybchenko siena_ev_init( 235e111ed8SAndrew Rybchenko __in efx_nic_t *enp); 245e111ed8SAndrew Rybchenko 255e111ed8SAndrew Rybchenko static void 265e111ed8SAndrew Rybchenko siena_ev_fini( 275e111ed8SAndrew Rybchenko __in efx_nic_t *enp); 285e111ed8SAndrew Rybchenko 295e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 305e111ed8SAndrew Rybchenko siena_ev_qcreate( 315e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 325e111ed8SAndrew Rybchenko __in unsigned int index, 335e111ed8SAndrew Rybchenko __in efsys_mem_t *esmp, 345e111ed8SAndrew Rybchenko __in size_t ndescs, 355e111ed8SAndrew Rybchenko __in uint32_t id, 365e111ed8SAndrew Rybchenko __in uint32_t us, 375e111ed8SAndrew Rybchenko __in uint32_t flags, 385e111ed8SAndrew Rybchenko __in efx_evq_t *eep); 395e111ed8SAndrew Rybchenko 405e111ed8SAndrew Rybchenko static void 415e111ed8SAndrew Rybchenko siena_ev_qdestroy( 425e111ed8SAndrew Rybchenko __in efx_evq_t *eep); 435e111ed8SAndrew Rybchenko 445e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 455e111ed8SAndrew Rybchenko siena_ev_qprime( 465e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 475e111ed8SAndrew Rybchenko __in unsigned int count); 485e111ed8SAndrew Rybchenko 495e111ed8SAndrew Rybchenko static void 505e111ed8SAndrew Rybchenko siena_ev_qpost( 515e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 525e111ed8SAndrew Rybchenko __in uint16_t data); 535e111ed8SAndrew Rybchenko 545e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 555e111ed8SAndrew Rybchenko siena_ev_qmoderate( 565e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 575e111ed8SAndrew Rybchenko __in unsigned int us); 585e111ed8SAndrew Rybchenko 595e111ed8SAndrew Rybchenko #if EFSYS_OPT_QSTATS 605e111ed8SAndrew Rybchenko static void 615e111ed8SAndrew Rybchenko siena_ev_qstats_update( 625e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 635e111ed8SAndrew Rybchenko __inout_ecount(EV_NQSTATS) efsys_stat_t *stat); 645e111ed8SAndrew Rybchenko 655e111ed8SAndrew Rybchenko #endif 665e111ed8SAndrew Rybchenko 675e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */ 685e111ed8SAndrew Rybchenko 69ad1e3ed8SAndrew Rybchenko #if EFX_OPTS_EF10() || EFSYS_OPT_SIENA 70ad1e3ed8SAndrew Rybchenko 71ad1e3ed8SAndrew Rybchenko static void 72ad1e3ed8SAndrew Rybchenko siena_ef10_ev_qpoll( 73ad1e3ed8SAndrew Rybchenko __in efx_evq_t *eep, 74ad1e3ed8SAndrew Rybchenko __inout unsigned int *countp, 75ad1e3ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 76ad1e3ed8SAndrew Rybchenko __in_opt void *arg); 77ad1e3ed8SAndrew Rybchenko 78ad1e3ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() || EFSYS_OPT_SIENA */ 79ad1e3ed8SAndrew Rybchenko 805e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA 815e111ed8SAndrew Rybchenko static const efx_ev_ops_t __efx_ev_siena_ops = { 825e111ed8SAndrew Rybchenko siena_ev_init, /* eevo_init */ 835e111ed8SAndrew Rybchenko siena_ev_fini, /* eevo_fini */ 845e111ed8SAndrew Rybchenko siena_ev_qcreate, /* eevo_qcreate */ 855e111ed8SAndrew Rybchenko siena_ev_qdestroy, /* eevo_qdestroy */ 865e111ed8SAndrew Rybchenko siena_ev_qprime, /* eevo_qprime */ 875e111ed8SAndrew Rybchenko siena_ev_qpost, /* eevo_qpost */ 88ad1e3ed8SAndrew Rybchenko siena_ef10_ev_qpoll, /* eevo_qpoll */ 895e111ed8SAndrew Rybchenko siena_ev_qmoderate, /* eevo_qmoderate */ 905e111ed8SAndrew Rybchenko #if EFSYS_OPT_QSTATS 915e111ed8SAndrew Rybchenko siena_ev_qstats_update, /* eevo_qstats_update */ 925e111ed8SAndrew Rybchenko #endif 935e111ed8SAndrew Rybchenko }; 945e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */ 955e111ed8SAndrew Rybchenko 965e111ed8SAndrew Rybchenko #if EFX_OPTS_EF10() 975e111ed8SAndrew Rybchenko static const efx_ev_ops_t __efx_ev_ef10_ops = { 985e111ed8SAndrew Rybchenko ef10_ev_init, /* eevo_init */ 995e111ed8SAndrew Rybchenko ef10_ev_fini, /* eevo_fini */ 1005e111ed8SAndrew Rybchenko ef10_ev_qcreate, /* eevo_qcreate */ 1015e111ed8SAndrew Rybchenko ef10_ev_qdestroy, /* eevo_qdestroy */ 1025e111ed8SAndrew Rybchenko ef10_ev_qprime, /* eevo_qprime */ 1035e111ed8SAndrew Rybchenko ef10_ev_qpost, /* eevo_qpost */ 104ad1e3ed8SAndrew Rybchenko siena_ef10_ev_qpoll, /* eevo_qpoll */ 1055e111ed8SAndrew Rybchenko ef10_ev_qmoderate, /* eevo_qmoderate */ 1065e111ed8SAndrew Rybchenko #if EFSYS_OPT_QSTATS 1075e111ed8SAndrew Rybchenko ef10_ev_qstats_update, /* eevo_qstats_update */ 1085e111ed8SAndrew Rybchenko #endif 1095e111ed8SAndrew Rybchenko }; 1105e111ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() */ 1115e111ed8SAndrew Rybchenko 112*b97bf1caSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD 113*b97bf1caSAndrew Rybchenko static const efx_ev_ops_t __efx_ev_rhead_ops = { 114*b97bf1caSAndrew Rybchenko rhead_ev_init, /* eevo_init */ 115*b97bf1caSAndrew Rybchenko rhead_ev_fini, /* eevo_fini */ 116*b97bf1caSAndrew Rybchenko rhead_ev_qcreate, /* eevo_qcreate */ 117*b97bf1caSAndrew Rybchenko rhead_ev_qdestroy, /* eevo_qdestroy */ 118*b97bf1caSAndrew Rybchenko rhead_ev_qprime, /* eevo_qprime */ 119*b97bf1caSAndrew Rybchenko rhead_ev_qpost, /* eevo_qpost */ 120*b97bf1caSAndrew Rybchenko rhead_ev_qpoll, /* eevo_qpoll */ 121*b97bf1caSAndrew Rybchenko rhead_ev_qmoderate, /* eevo_qmoderate */ 122*b97bf1caSAndrew Rybchenko #if EFSYS_OPT_QSTATS 123*b97bf1caSAndrew Rybchenko rhead_ev_qstats_update, /* eevo_qstats_update */ 124*b97bf1caSAndrew Rybchenko #endif 125*b97bf1caSAndrew Rybchenko }; 126*b97bf1caSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */ 127*b97bf1caSAndrew Rybchenko 1285e111ed8SAndrew Rybchenko 1295e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 1305e111ed8SAndrew Rybchenko efx_ev_init( 1315e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 1325e111ed8SAndrew Rybchenko { 1335e111ed8SAndrew Rybchenko const efx_ev_ops_t *eevop; 1345e111ed8SAndrew Rybchenko efx_rc_t rc; 1355e111ed8SAndrew Rybchenko 1365e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1375e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 1385e111ed8SAndrew Rybchenko 1395e111ed8SAndrew Rybchenko if (enp->en_mod_flags & EFX_MOD_EV) { 1405e111ed8SAndrew Rybchenko rc = EINVAL; 1415e111ed8SAndrew Rybchenko goto fail1; 1425e111ed8SAndrew Rybchenko } 1435e111ed8SAndrew Rybchenko 1445e111ed8SAndrew Rybchenko switch (enp->en_family) { 1455e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA 1465e111ed8SAndrew Rybchenko case EFX_FAMILY_SIENA: 1475e111ed8SAndrew Rybchenko eevop = &__efx_ev_siena_ops; 1485e111ed8SAndrew Rybchenko break; 1495e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */ 1505e111ed8SAndrew Rybchenko 1515e111ed8SAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON 1525e111ed8SAndrew Rybchenko case EFX_FAMILY_HUNTINGTON: 1535e111ed8SAndrew Rybchenko eevop = &__efx_ev_ef10_ops; 1545e111ed8SAndrew Rybchenko break; 1555e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */ 1565e111ed8SAndrew Rybchenko 1575e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD 1585e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD: 1595e111ed8SAndrew Rybchenko eevop = &__efx_ev_ef10_ops; 1605e111ed8SAndrew Rybchenko break; 1615e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */ 1625e111ed8SAndrew Rybchenko 1635e111ed8SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2 1645e111ed8SAndrew Rybchenko case EFX_FAMILY_MEDFORD2: 1655e111ed8SAndrew Rybchenko eevop = &__efx_ev_ef10_ops; 1665e111ed8SAndrew Rybchenko break; 1675e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */ 1685e111ed8SAndrew Rybchenko 169*b97bf1caSAndrew Rybchenko #if EFSYS_OPT_RIVERHEAD 170*b97bf1caSAndrew Rybchenko case EFX_FAMILY_RIVERHEAD: 171*b97bf1caSAndrew Rybchenko eevop = &__efx_ev_rhead_ops; 172*b97bf1caSAndrew Rybchenko break; 173*b97bf1caSAndrew Rybchenko #endif /* EFSYS_OPT_RIVERHEAD */ 174*b97bf1caSAndrew Rybchenko 1755e111ed8SAndrew Rybchenko default: 1765e111ed8SAndrew Rybchenko EFSYS_ASSERT(0); 1775e111ed8SAndrew Rybchenko rc = ENOTSUP; 1785e111ed8SAndrew Rybchenko goto fail1; 1795e111ed8SAndrew Rybchenko } 1805e111ed8SAndrew Rybchenko 1815e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0); 1825e111ed8SAndrew Rybchenko 1835e111ed8SAndrew Rybchenko if ((rc = eevop->eevo_init(enp)) != 0) 1845e111ed8SAndrew Rybchenko goto fail2; 1855e111ed8SAndrew Rybchenko 1865e111ed8SAndrew Rybchenko enp->en_eevop = eevop; 1875e111ed8SAndrew Rybchenko enp->en_mod_flags |= EFX_MOD_EV; 1885e111ed8SAndrew Rybchenko return (0); 1895e111ed8SAndrew Rybchenko 1905e111ed8SAndrew Rybchenko fail2: 1915e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 1925e111ed8SAndrew Rybchenko 1935e111ed8SAndrew Rybchenko fail1: 1945e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 1955e111ed8SAndrew Rybchenko 1965e111ed8SAndrew Rybchenko enp->en_eevop = NULL; 1975e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_EV; 1985e111ed8SAndrew Rybchenko return (rc); 1995e111ed8SAndrew Rybchenko } 2005e111ed8SAndrew Rybchenko 2015e111ed8SAndrew Rybchenko __checkReturn size_t 2025e111ed8SAndrew Rybchenko efx_evq_size( 2035e111ed8SAndrew Rybchenko __in const efx_nic_t *enp, 2045e111ed8SAndrew Rybchenko __in unsigned int ndescs) 2055e111ed8SAndrew Rybchenko { 2065e111ed8SAndrew Rybchenko const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2075e111ed8SAndrew Rybchenko 2085e111ed8SAndrew Rybchenko return (ndescs * encp->enc_ev_desc_size); 2095e111ed8SAndrew Rybchenko } 2105e111ed8SAndrew Rybchenko 2115e111ed8SAndrew Rybchenko __checkReturn unsigned int 2125e111ed8SAndrew Rybchenko efx_evq_nbufs( 2135e111ed8SAndrew Rybchenko __in const efx_nic_t *enp, 2145e111ed8SAndrew Rybchenko __in unsigned int ndescs) 2155e111ed8SAndrew Rybchenko { 2165e111ed8SAndrew Rybchenko return (EFX_DIV_ROUND_UP(efx_evq_size(enp, ndescs), EFX_BUF_SIZE)); 2175e111ed8SAndrew Rybchenko } 2185e111ed8SAndrew Rybchenko 2195e111ed8SAndrew Rybchenko void 2205e111ed8SAndrew Rybchenko efx_ev_fini( 2215e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 2225e111ed8SAndrew Rybchenko { 2235e111ed8SAndrew Rybchenko const efx_ev_ops_t *eevop = enp->en_eevop; 2245e111ed8SAndrew Rybchenko 2255e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 2265e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 2275e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV); 2285e111ed8SAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 2295e111ed8SAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 2305e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_ev_qcount, ==, 0); 2315e111ed8SAndrew Rybchenko 2325e111ed8SAndrew Rybchenko eevop->eevo_fini(enp); 2335e111ed8SAndrew Rybchenko 2345e111ed8SAndrew Rybchenko enp->en_eevop = NULL; 2355e111ed8SAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_EV; 2365e111ed8SAndrew Rybchenko } 2375e111ed8SAndrew Rybchenko 2385e111ed8SAndrew Rybchenko 2395e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 2405e111ed8SAndrew Rybchenko efx_ev_qcreate( 2415e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 2425e111ed8SAndrew Rybchenko __in unsigned int index, 2435e111ed8SAndrew Rybchenko __in efsys_mem_t *esmp, 2445e111ed8SAndrew Rybchenko __in size_t ndescs, 2455e111ed8SAndrew Rybchenko __in uint32_t id, 2465e111ed8SAndrew Rybchenko __in uint32_t us, 2475e111ed8SAndrew Rybchenko __in uint32_t flags, 2485e111ed8SAndrew Rybchenko __deref_out efx_evq_t **eepp) 2495e111ed8SAndrew Rybchenko { 2505e111ed8SAndrew Rybchenko const efx_ev_ops_t *eevop = enp->en_eevop; 2515e111ed8SAndrew Rybchenko efx_evq_t *eep; 2525e111ed8SAndrew Rybchenko const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2535e111ed8SAndrew Rybchenko efx_rc_t rc; 2545e111ed8SAndrew Rybchenko 2555e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 2565e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_EV); 2575e111ed8SAndrew Rybchenko 2585e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_ev_qcount + 1, <, 2595e111ed8SAndrew Rybchenko enp->en_nic_cfg.enc_evq_limit); 2605e111ed8SAndrew Rybchenko 2612e5819a5SAndrew Rybchenko if (index >= encp->enc_evq_limit) { 2622e5819a5SAndrew Rybchenko rc = EINVAL; 2632e5819a5SAndrew Rybchenko goto fail1; 2642e5819a5SAndrew Rybchenko } 2652e5819a5SAndrew Rybchenko 2662e5819a5SAndrew Rybchenko if (us > encp->enc_evq_timer_max_us) { 2672e5819a5SAndrew Rybchenko rc = EINVAL; 2682e5819a5SAndrew Rybchenko goto fail2; 2692e5819a5SAndrew Rybchenko } 2702e5819a5SAndrew Rybchenko 2715e111ed8SAndrew Rybchenko switch (flags & EFX_EVQ_FLAGS_NOTIFY_MASK) { 2725e111ed8SAndrew Rybchenko case EFX_EVQ_FLAGS_NOTIFY_INTERRUPT: 2735e111ed8SAndrew Rybchenko break; 2745e111ed8SAndrew Rybchenko case EFX_EVQ_FLAGS_NOTIFY_DISABLED: 2755e111ed8SAndrew Rybchenko if (us != 0) { 2765e111ed8SAndrew Rybchenko rc = EINVAL; 2772e5819a5SAndrew Rybchenko goto fail3; 2785e111ed8SAndrew Rybchenko } 2795e111ed8SAndrew Rybchenko break; 2805e111ed8SAndrew Rybchenko default: 2815e111ed8SAndrew Rybchenko rc = EINVAL; 2822e5819a5SAndrew Rybchenko goto fail4; 2835e111ed8SAndrew Rybchenko } 2845e111ed8SAndrew Rybchenko 2855e111ed8SAndrew Rybchenko EFSYS_ASSERT(ISP2(encp->enc_evq_max_nevs)); 2865e111ed8SAndrew Rybchenko EFSYS_ASSERT(ISP2(encp->enc_evq_min_nevs)); 2875e111ed8SAndrew Rybchenko 2885e111ed8SAndrew Rybchenko if (!ISP2(ndescs) || 2895e111ed8SAndrew Rybchenko ndescs < encp->enc_evq_min_nevs || 2905e111ed8SAndrew Rybchenko ndescs > encp->enc_evq_max_nevs) { 2915e111ed8SAndrew Rybchenko rc = EINVAL; 2922e5819a5SAndrew Rybchenko goto fail5; 2935e111ed8SAndrew Rybchenko } 2945e111ed8SAndrew Rybchenko 2955e111ed8SAndrew Rybchenko /* Allocate an EVQ object */ 2965e111ed8SAndrew Rybchenko EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_evq_t), eep); 2975e111ed8SAndrew Rybchenko if (eep == NULL) { 2985e111ed8SAndrew Rybchenko rc = ENOMEM; 2992e5819a5SAndrew Rybchenko goto fail6; 3005e111ed8SAndrew Rybchenko } 3015e111ed8SAndrew Rybchenko 3025e111ed8SAndrew Rybchenko eep->ee_magic = EFX_EVQ_MAGIC; 3035e111ed8SAndrew Rybchenko eep->ee_enp = enp; 3045e111ed8SAndrew Rybchenko eep->ee_index = index; 3055e111ed8SAndrew Rybchenko eep->ee_mask = ndescs - 1; 3065e111ed8SAndrew Rybchenko eep->ee_flags = flags; 3075e111ed8SAndrew Rybchenko eep->ee_esmp = esmp; 3085e111ed8SAndrew Rybchenko 3095e111ed8SAndrew Rybchenko /* 3105e111ed8SAndrew Rybchenko * Set outputs before the queue is created because interrupts may be 3115e111ed8SAndrew Rybchenko * raised for events immediately after the queue is created, before the 3125e111ed8SAndrew Rybchenko * function call below returns. See bug58606. 3135e111ed8SAndrew Rybchenko * 3145e111ed8SAndrew Rybchenko * The eepp pointer passed in by the client must therefore point to data 3155e111ed8SAndrew Rybchenko * shared with the client's event processing context. 3165e111ed8SAndrew Rybchenko */ 3175e111ed8SAndrew Rybchenko enp->en_ev_qcount++; 3185e111ed8SAndrew Rybchenko *eepp = eep; 3195e111ed8SAndrew Rybchenko 3205e111ed8SAndrew Rybchenko if ((rc = eevop->eevo_qcreate(enp, index, esmp, ndescs, id, us, flags, 3215e111ed8SAndrew Rybchenko eep)) != 0) 3222e5819a5SAndrew Rybchenko goto fail7; 3235e111ed8SAndrew Rybchenko 3245e111ed8SAndrew Rybchenko return (0); 3255e111ed8SAndrew Rybchenko 3262e5819a5SAndrew Rybchenko fail7: 3272e5819a5SAndrew Rybchenko EFSYS_PROBE(fail7); 3285e111ed8SAndrew Rybchenko 3295e111ed8SAndrew Rybchenko *eepp = NULL; 3305e111ed8SAndrew Rybchenko enp->en_ev_qcount--; 3315e111ed8SAndrew Rybchenko EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep); 3322e5819a5SAndrew Rybchenko fail6: 3332e5819a5SAndrew Rybchenko EFSYS_PROBE(fail6); 3342e5819a5SAndrew Rybchenko fail5: 3352e5819a5SAndrew Rybchenko EFSYS_PROBE(fail5); 3365e111ed8SAndrew Rybchenko fail4: 3375e111ed8SAndrew Rybchenko EFSYS_PROBE(fail4); 3385e111ed8SAndrew Rybchenko fail3: 3395e111ed8SAndrew Rybchenko EFSYS_PROBE(fail3); 3405e111ed8SAndrew Rybchenko fail2: 3415e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 3425e111ed8SAndrew Rybchenko fail1: 3435e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 3445e111ed8SAndrew Rybchenko return (rc); 3455e111ed8SAndrew Rybchenko } 3465e111ed8SAndrew Rybchenko 3475e111ed8SAndrew Rybchenko void 3485e111ed8SAndrew Rybchenko efx_ev_qdestroy( 3495e111ed8SAndrew Rybchenko __in efx_evq_t *eep) 3505e111ed8SAndrew Rybchenko { 3515e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 3525e111ed8SAndrew Rybchenko const efx_ev_ops_t *eevop = enp->en_eevop; 3535e111ed8SAndrew Rybchenko 3545e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 3555e111ed8SAndrew Rybchenko 3565e111ed8SAndrew Rybchenko EFSYS_ASSERT(enp->en_ev_qcount != 0); 3575e111ed8SAndrew Rybchenko --enp->en_ev_qcount; 3585e111ed8SAndrew Rybchenko 3595e111ed8SAndrew Rybchenko eevop->eevo_qdestroy(eep); 3605e111ed8SAndrew Rybchenko 3615e111ed8SAndrew Rybchenko /* Free the EVQ object */ 3625e111ed8SAndrew Rybchenko EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_evq_t), eep); 3635e111ed8SAndrew Rybchenko } 3645e111ed8SAndrew Rybchenko 3655e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 3665e111ed8SAndrew Rybchenko efx_ev_qprime( 3675e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 3685e111ed8SAndrew Rybchenko __in unsigned int count) 3695e111ed8SAndrew Rybchenko { 3705e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 3715e111ed8SAndrew Rybchenko const efx_ev_ops_t *eevop = enp->en_eevop; 3725e111ed8SAndrew Rybchenko efx_rc_t rc; 3735e111ed8SAndrew Rybchenko 3745e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 3755e111ed8SAndrew Rybchenko 3765e111ed8SAndrew Rybchenko if (!(enp->en_mod_flags & EFX_MOD_INTR)) { 3775e111ed8SAndrew Rybchenko rc = EINVAL; 3785e111ed8SAndrew Rybchenko goto fail1; 3795e111ed8SAndrew Rybchenko } 3805e111ed8SAndrew Rybchenko 3815e111ed8SAndrew Rybchenko if ((rc = eevop->eevo_qprime(eep, count)) != 0) 3825e111ed8SAndrew Rybchenko goto fail2; 3835e111ed8SAndrew Rybchenko 3845e111ed8SAndrew Rybchenko return (0); 3855e111ed8SAndrew Rybchenko 3865e111ed8SAndrew Rybchenko fail2: 3875e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 3885e111ed8SAndrew Rybchenko fail1: 3895e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 3905e111ed8SAndrew Rybchenko return (rc); 3915e111ed8SAndrew Rybchenko } 3925e111ed8SAndrew Rybchenko 3935e111ed8SAndrew Rybchenko __checkReturn boolean_t 3945e111ed8SAndrew Rybchenko efx_ev_qpending( 3955e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 3965e111ed8SAndrew Rybchenko __in unsigned int count) 3975e111ed8SAndrew Rybchenko { 3985e111ed8SAndrew Rybchenko size_t offset; 3995e111ed8SAndrew Rybchenko efx_qword_t qword; 4005e111ed8SAndrew Rybchenko 4015e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 4025e111ed8SAndrew Rybchenko 4035e111ed8SAndrew Rybchenko offset = (count & eep->ee_mask) * sizeof (efx_qword_t); 4045e111ed8SAndrew Rybchenko EFSYS_MEM_READQ(eep->ee_esmp, offset, &qword); 4055e111ed8SAndrew Rybchenko 4065e111ed8SAndrew Rybchenko return (EFX_EV_PRESENT(qword)); 4075e111ed8SAndrew Rybchenko } 4085e111ed8SAndrew Rybchenko 4095e111ed8SAndrew Rybchenko #if EFSYS_OPT_EV_PREFETCH 4105e111ed8SAndrew Rybchenko 4115e111ed8SAndrew Rybchenko void 4125e111ed8SAndrew Rybchenko efx_ev_qprefetch( 4135e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 4145e111ed8SAndrew Rybchenko __in unsigned int count) 4155e111ed8SAndrew Rybchenko { 4165e111ed8SAndrew Rybchenko unsigned int offset; 4175e111ed8SAndrew Rybchenko 4185e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 4195e111ed8SAndrew Rybchenko 4205e111ed8SAndrew Rybchenko offset = (count & eep->ee_mask) * sizeof (efx_qword_t); 4215e111ed8SAndrew Rybchenko EFSYS_MEM_PREFETCH(eep->ee_esmp, offset); 4225e111ed8SAndrew Rybchenko } 4235e111ed8SAndrew Rybchenko 4245e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_EV_PREFETCH */ 4255e111ed8SAndrew Rybchenko 4265e111ed8SAndrew Rybchenko void 4275e111ed8SAndrew Rybchenko efx_ev_qpoll( 4285e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 4295e111ed8SAndrew Rybchenko __inout unsigned int *countp, 4305e111ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 4315e111ed8SAndrew Rybchenko __in_opt void *arg) 4325e111ed8SAndrew Rybchenko { 433ad1e3ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 434ad1e3ed8SAndrew Rybchenko const efx_ev_ops_t *eevop = enp->en_eevop; 4355e111ed8SAndrew Rybchenko 4365e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 4375e111ed8SAndrew Rybchenko 438ad1e3ed8SAndrew Rybchenko EFSYS_ASSERT(eevop != NULL && 439ad1e3ed8SAndrew Rybchenko eevop->eevo_qpoll != NULL); 4405e111ed8SAndrew Rybchenko 441ad1e3ed8SAndrew Rybchenko eevop->eevo_qpoll(eep, countp, eecp, arg); 4425e111ed8SAndrew Rybchenko } 4435e111ed8SAndrew Rybchenko 4445e111ed8SAndrew Rybchenko void 4455e111ed8SAndrew Rybchenko efx_ev_qpost( 4465e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 4475e111ed8SAndrew Rybchenko __in uint16_t data) 4485e111ed8SAndrew Rybchenko { 4495e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 4505e111ed8SAndrew Rybchenko const efx_ev_ops_t *eevop = enp->en_eevop; 4515e111ed8SAndrew Rybchenko 4525e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 4535e111ed8SAndrew Rybchenko 4545e111ed8SAndrew Rybchenko EFSYS_ASSERT(eevop != NULL && 4555e111ed8SAndrew Rybchenko eevop->eevo_qpost != NULL); 4565e111ed8SAndrew Rybchenko 4575e111ed8SAndrew Rybchenko eevop->eevo_qpost(eep, data); 4585e111ed8SAndrew Rybchenko } 4595e111ed8SAndrew Rybchenko 4605e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 4615e111ed8SAndrew Rybchenko efx_ev_usecs_to_ticks( 4625e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 4635e111ed8SAndrew Rybchenko __in unsigned int us, 4645e111ed8SAndrew Rybchenko __out unsigned int *ticksp) 4655e111ed8SAndrew Rybchenko { 4665e111ed8SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 4675e111ed8SAndrew Rybchenko unsigned int ticks; 4685e111ed8SAndrew Rybchenko efx_rc_t rc; 4695e111ed8SAndrew Rybchenko 4705e111ed8SAndrew Rybchenko if (encp->enc_evq_timer_quantum_ns == 0) { 4715e111ed8SAndrew Rybchenko rc = ENOTSUP; 4725e111ed8SAndrew Rybchenko goto fail1; 4735e111ed8SAndrew Rybchenko } 4745e111ed8SAndrew Rybchenko 4755e111ed8SAndrew Rybchenko /* Convert microseconds to a timer tick count */ 4765e111ed8SAndrew Rybchenko if (us == 0) 4775e111ed8SAndrew Rybchenko ticks = 0; 4785e111ed8SAndrew Rybchenko else if (us * 1000 < encp->enc_evq_timer_quantum_ns) 4795e111ed8SAndrew Rybchenko ticks = 1; /* Never round down to zero */ 4805e111ed8SAndrew Rybchenko else 4815e111ed8SAndrew Rybchenko ticks = us * 1000 / encp->enc_evq_timer_quantum_ns; 4825e111ed8SAndrew Rybchenko 4835e111ed8SAndrew Rybchenko *ticksp = ticks; 4845e111ed8SAndrew Rybchenko return (0); 4855e111ed8SAndrew Rybchenko 4865e111ed8SAndrew Rybchenko fail1: 4875e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 4885e111ed8SAndrew Rybchenko return (rc); 4895e111ed8SAndrew Rybchenko } 4905e111ed8SAndrew Rybchenko 4915e111ed8SAndrew Rybchenko __checkReturn efx_rc_t 4925e111ed8SAndrew Rybchenko efx_ev_qmoderate( 4935e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 4945e111ed8SAndrew Rybchenko __in unsigned int us) 4955e111ed8SAndrew Rybchenko { 4965e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 4975e111ed8SAndrew Rybchenko const efx_ev_ops_t *eevop = enp->en_eevop; 4985e111ed8SAndrew Rybchenko efx_rc_t rc; 4995e111ed8SAndrew Rybchenko 5005e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 5015e111ed8SAndrew Rybchenko 5025e111ed8SAndrew Rybchenko if ((eep->ee_flags & EFX_EVQ_FLAGS_NOTIFY_MASK) == 5035e111ed8SAndrew Rybchenko EFX_EVQ_FLAGS_NOTIFY_DISABLED) { 5045e111ed8SAndrew Rybchenko rc = EINVAL; 5055e111ed8SAndrew Rybchenko goto fail1; 5065e111ed8SAndrew Rybchenko } 5075e111ed8SAndrew Rybchenko 5085e111ed8SAndrew Rybchenko if ((rc = eevop->eevo_qmoderate(eep, us)) != 0) 5095e111ed8SAndrew Rybchenko goto fail2; 5105e111ed8SAndrew Rybchenko 5115e111ed8SAndrew Rybchenko return (0); 5125e111ed8SAndrew Rybchenko 5135e111ed8SAndrew Rybchenko fail2: 5145e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 5155e111ed8SAndrew Rybchenko fail1: 5165e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 5175e111ed8SAndrew Rybchenko return (rc); 5185e111ed8SAndrew Rybchenko } 5195e111ed8SAndrew Rybchenko 5205e111ed8SAndrew Rybchenko #if EFSYS_OPT_QSTATS 5215e111ed8SAndrew Rybchenko void 5225e111ed8SAndrew Rybchenko efx_ev_qstats_update( 5235e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 5245e111ed8SAndrew Rybchenko __inout_ecount(EV_NQSTATS) efsys_stat_t *stat) 5255e111ed8SAndrew Rybchenko 5265e111ed8SAndrew Rybchenko { efx_nic_t *enp = eep->ee_enp; 5275e111ed8SAndrew Rybchenko const efx_ev_ops_t *eevop = enp->en_eevop; 5285e111ed8SAndrew Rybchenko 5295e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 5305e111ed8SAndrew Rybchenko 5315e111ed8SAndrew Rybchenko eevop->eevo_qstats_update(eep, stat); 5325e111ed8SAndrew Rybchenko } 5335e111ed8SAndrew Rybchenko 5345e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_QSTATS */ 5355e111ed8SAndrew Rybchenko 5365e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA 5375e111ed8SAndrew Rybchenko 5385e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 5395e111ed8SAndrew Rybchenko siena_ev_init( 5405e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 5415e111ed8SAndrew Rybchenko { 5425e111ed8SAndrew Rybchenko efx_oword_t oword; 5435e111ed8SAndrew Rybchenko 5445e111ed8SAndrew Rybchenko /* 5455e111ed8SAndrew Rybchenko * Program the event queue for receive and transmit queue 5465e111ed8SAndrew Rybchenko * flush events. 5475e111ed8SAndrew Rybchenko */ 5485e111ed8SAndrew Rybchenko EFX_BAR_READO(enp, FR_AZ_DP_CTRL_REG, &oword); 5495e111ed8SAndrew Rybchenko EFX_SET_OWORD_FIELD(oword, FRF_AZ_FLS_EVQ_ID, 0); 5505e111ed8SAndrew Rybchenko EFX_BAR_WRITEO(enp, FR_AZ_DP_CTRL_REG, &oword); 5515e111ed8SAndrew Rybchenko 5525e111ed8SAndrew Rybchenko return (0); 5535e111ed8SAndrew Rybchenko 5545e111ed8SAndrew Rybchenko } 5555e111ed8SAndrew Rybchenko 5565e111ed8SAndrew Rybchenko static __checkReturn boolean_t 5575e111ed8SAndrew Rybchenko siena_ev_rx_not_ok( 5585e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 5595e111ed8SAndrew Rybchenko __in efx_qword_t *eqp, 5605e111ed8SAndrew Rybchenko __in uint32_t label, 5615e111ed8SAndrew Rybchenko __in uint32_t id, 5625e111ed8SAndrew Rybchenko __inout uint16_t *flagsp) 5635e111ed8SAndrew Rybchenko { 5645e111ed8SAndrew Rybchenko boolean_t ignore = B_FALSE; 5655e111ed8SAndrew Rybchenko 5665e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_TOBE_DISC) != 0) { 5675e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_TOBE_DISC); 5685e111ed8SAndrew Rybchenko EFSYS_PROBE(tobe_disc); 5695e111ed8SAndrew Rybchenko /* 5705e111ed8SAndrew Rybchenko * Assume this is a unicast address mismatch, unless below 5715e111ed8SAndrew Rybchenko * we find either FSF_AZ_RX_EV_ETH_CRC_ERR or 5725e111ed8SAndrew Rybchenko * EV_RX_PAUSE_FRM_ERR is set. 5735e111ed8SAndrew Rybchenko */ 5745e111ed8SAndrew Rybchenko (*flagsp) |= EFX_ADDR_MISMATCH; 5755e111ed8SAndrew Rybchenko } 5765e111ed8SAndrew Rybchenko 5775e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_FRM_TRUNC) != 0) { 5785e111ed8SAndrew Rybchenko EFSYS_PROBE2(frm_trunc, uint32_t, label, uint32_t, id); 5795e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_FRM_TRUNC); 5805e111ed8SAndrew Rybchenko (*flagsp) |= EFX_DISCARD; 5815e111ed8SAndrew Rybchenko 5825e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER 5835e111ed8SAndrew Rybchenko /* 5845e111ed8SAndrew Rybchenko * Lookout for payload queue ran dry errors and ignore them. 5855e111ed8SAndrew Rybchenko * 5865e111ed8SAndrew Rybchenko * Sadly for the header/data split cases, the descriptor 5875e111ed8SAndrew Rybchenko * pointer in this event refers to the header queue and 5885e111ed8SAndrew Rybchenko * therefore cannot be easily detected as duplicate. 5895e111ed8SAndrew Rybchenko * So we drop these and rely on the receive processing seeing 5905e111ed8SAndrew Rybchenko * a subsequent packet with FSF_AZ_RX_EV_SOP set to discard 5915e111ed8SAndrew Rybchenko * the partially received packet. 5925e111ed8SAndrew Rybchenko */ 5935e111ed8SAndrew Rybchenko if ((EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_SOP) == 0) && 5945e111ed8SAndrew Rybchenko (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_JUMBO_CONT) == 0) && 5955e111ed8SAndrew Rybchenko (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_BYTE_CNT) == 0)) 5965e111ed8SAndrew Rybchenko ignore = B_TRUE; 5975e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCATTER */ 5985e111ed8SAndrew Rybchenko } 5995e111ed8SAndrew Rybchenko 6005e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_ETH_CRC_ERR) != 0) { 6015e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_ETH_CRC_ERR); 6025e111ed8SAndrew Rybchenko EFSYS_PROBE(crc_err); 6035e111ed8SAndrew Rybchenko (*flagsp) &= ~EFX_ADDR_MISMATCH; 6045e111ed8SAndrew Rybchenko (*flagsp) |= EFX_DISCARD; 6055e111ed8SAndrew Rybchenko } 6065e111ed8SAndrew Rybchenko 6075e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PAUSE_FRM_ERR) != 0) { 6085e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_PAUSE_FRM_ERR); 6095e111ed8SAndrew Rybchenko EFSYS_PROBE(pause_frm_err); 6105e111ed8SAndrew Rybchenko (*flagsp) &= ~EFX_ADDR_MISMATCH; 6115e111ed8SAndrew Rybchenko (*flagsp) |= EFX_DISCARD; 6125e111ed8SAndrew Rybchenko } 6135e111ed8SAndrew Rybchenko 6145e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_BUF_OWNER_ID_ERR) != 0) { 6155e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_BUF_OWNER_ID_ERR); 6165e111ed8SAndrew Rybchenko EFSYS_PROBE(owner_id_err); 6175e111ed8SAndrew Rybchenko (*flagsp) |= EFX_DISCARD; 6185e111ed8SAndrew Rybchenko } 6195e111ed8SAndrew Rybchenko 6205e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR) != 0) { 6215e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_IPV4_HDR_CHKSUM_ERR); 6225e111ed8SAndrew Rybchenko EFSYS_PROBE(ipv4_err); 6235e111ed8SAndrew Rybchenko (*flagsp) &= ~EFX_CKSUM_IPV4; 6245e111ed8SAndrew Rybchenko } 6255e111ed8SAndrew Rybchenko 6265e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR) != 0) { 6275e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_UDP_CHKSUM_ERR); 6285e111ed8SAndrew Rybchenko EFSYS_PROBE(udp_chk_err); 6295e111ed8SAndrew Rybchenko (*flagsp) &= ~EFX_CKSUM_TCPUDP; 6305e111ed8SAndrew Rybchenko } 6315e111ed8SAndrew Rybchenko 6325e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_IP_FRAG_ERR) != 0) { 6335e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_IP_FRAG_ERR); 6345e111ed8SAndrew Rybchenko 6355e111ed8SAndrew Rybchenko /* 6365e111ed8SAndrew Rybchenko * If IP is fragmented FSF_AZ_RX_EV_IP_FRAG_ERR is set. This 6375e111ed8SAndrew Rybchenko * causes FSF_AZ_RX_EV_PKT_OK to be clear. This is not an error 6385e111ed8SAndrew Rybchenko * condition. 6395e111ed8SAndrew Rybchenko */ 6405e111ed8SAndrew Rybchenko (*flagsp) &= ~(EFX_PKT_TCP | EFX_PKT_UDP | EFX_CKSUM_TCPUDP); 6415e111ed8SAndrew Rybchenko } 6425e111ed8SAndrew Rybchenko 6435e111ed8SAndrew Rybchenko return (ignore); 6445e111ed8SAndrew Rybchenko } 6455e111ed8SAndrew Rybchenko 6465e111ed8SAndrew Rybchenko static __checkReturn boolean_t 6475e111ed8SAndrew Rybchenko siena_ev_rx( 6485e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 6495e111ed8SAndrew Rybchenko __in efx_qword_t *eqp, 6505e111ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 6515e111ed8SAndrew Rybchenko __in_opt void *arg) 6525e111ed8SAndrew Rybchenko { 6535e111ed8SAndrew Rybchenko uint32_t id; 6545e111ed8SAndrew Rybchenko uint32_t size; 6555e111ed8SAndrew Rybchenko uint32_t label; 6565e111ed8SAndrew Rybchenko boolean_t ok; 6575e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER 6585e111ed8SAndrew Rybchenko boolean_t sop; 6595e111ed8SAndrew Rybchenko boolean_t jumbo_cont; 6605e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCATTER */ 6615e111ed8SAndrew Rybchenko uint32_t hdr_type; 6625e111ed8SAndrew Rybchenko boolean_t is_v6; 6635e111ed8SAndrew Rybchenko uint16_t flags; 6645e111ed8SAndrew Rybchenko boolean_t ignore; 6655e111ed8SAndrew Rybchenko boolean_t should_abort; 6665e111ed8SAndrew Rybchenko 6675e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX); 6685e111ed8SAndrew Rybchenko 6695e111ed8SAndrew Rybchenko /* Basic packet information */ 6705e111ed8SAndrew Rybchenko id = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_DESC_PTR); 6715e111ed8SAndrew Rybchenko size = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_BYTE_CNT); 6725e111ed8SAndrew Rybchenko label = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_Q_LABEL); 6735e111ed8SAndrew Rybchenko ok = (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PKT_OK) != 0); 6745e111ed8SAndrew Rybchenko 6755e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER 6765e111ed8SAndrew Rybchenko sop = (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_SOP) != 0); 6775e111ed8SAndrew Rybchenko jumbo_cont = (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_JUMBO_CONT) != 0); 6785e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCATTER */ 6795e111ed8SAndrew Rybchenko 6805e111ed8SAndrew Rybchenko hdr_type = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_HDR_TYPE); 6815e111ed8SAndrew Rybchenko 6825e111ed8SAndrew Rybchenko is_v6 = (EFX_QWORD_FIELD(*eqp, FSF_CZ_RX_EV_IPV6_PKT) != 0); 6835e111ed8SAndrew Rybchenko 6845e111ed8SAndrew Rybchenko /* 6855e111ed8SAndrew Rybchenko * If packet is marked as OK and packet type is TCP/IP or 6865e111ed8SAndrew Rybchenko * UDP/IP or other IP, then we can rely on the hardware checksums. 6875e111ed8SAndrew Rybchenko */ 6885e111ed8SAndrew Rybchenko switch (hdr_type) { 6895e111ed8SAndrew Rybchenko case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_TCP: 6905e111ed8SAndrew Rybchenko flags = EFX_PKT_TCP | EFX_CKSUM_TCPUDP; 6915e111ed8SAndrew Rybchenko if (is_v6) { 6925e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV6); 6935e111ed8SAndrew Rybchenko flags |= EFX_PKT_IPV6; 6945e111ed8SAndrew Rybchenko } else { 6955e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_TCP_IPV4); 6965e111ed8SAndrew Rybchenko flags |= EFX_PKT_IPV4 | EFX_CKSUM_IPV4; 6975e111ed8SAndrew Rybchenko } 6985e111ed8SAndrew Rybchenko break; 6995e111ed8SAndrew Rybchenko 7005e111ed8SAndrew Rybchenko case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_UDP: 7015e111ed8SAndrew Rybchenko flags = EFX_PKT_UDP | EFX_CKSUM_TCPUDP; 7025e111ed8SAndrew Rybchenko if (is_v6) { 7035e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV6); 7045e111ed8SAndrew Rybchenko flags |= EFX_PKT_IPV6; 7055e111ed8SAndrew Rybchenko } else { 7065e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_UDP_IPV4); 7075e111ed8SAndrew Rybchenko flags |= EFX_PKT_IPV4 | EFX_CKSUM_IPV4; 7085e111ed8SAndrew Rybchenko } 7095e111ed8SAndrew Rybchenko break; 7105e111ed8SAndrew Rybchenko 7115e111ed8SAndrew Rybchenko case FSE_AZ_RX_EV_HDR_TYPE_IPV4V6_OTHER: 7125e111ed8SAndrew Rybchenko if (is_v6) { 7135e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV6); 7145e111ed8SAndrew Rybchenko flags = EFX_PKT_IPV6; 7155e111ed8SAndrew Rybchenko } else { 7165e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_OTHER_IPV4); 7175e111ed8SAndrew Rybchenko flags = EFX_PKT_IPV4 | EFX_CKSUM_IPV4; 7185e111ed8SAndrew Rybchenko } 7195e111ed8SAndrew Rybchenko break; 7205e111ed8SAndrew Rybchenko 7215e111ed8SAndrew Rybchenko case FSE_AZ_RX_EV_HDR_TYPE_OTHER: 7225e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_NON_IP); 7235e111ed8SAndrew Rybchenko flags = 0; 7245e111ed8SAndrew Rybchenko break; 7255e111ed8SAndrew Rybchenko 7265e111ed8SAndrew Rybchenko default: 7275e111ed8SAndrew Rybchenko EFSYS_ASSERT(B_FALSE); 7285e111ed8SAndrew Rybchenko flags = 0; 7295e111ed8SAndrew Rybchenko break; 7305e111ed8SAndrew Rybchenko } 7315e111ed8SAndrew Rybchenko 7325e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCATTER 7335e111ed8SAndrew Rybchenko /* Report scatter and header/lookahead split buffer flags */ 7345e111ed8SAndrew Rybchenko if (sop) 7355e111ed8SAndrew Rybchenko flags |= EFX_PKT_START; 7365e111ed8SAndrew Rybchenko if (jumbo_cont) 7375e111ed8SAndrew Rybchenko flags |= EFX_PKT_CONT; 7385e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_RX_SCATTER */ 7395e111ed8SAndrew Rybchenko 7405e111ed8SAndrew Rybchenko /* Detect errors included in the FSF_AZ_RX_EV_PKT_OK indication */ 7415e111ed8SAndrew Rybchenko if (!ok) { 7425e111ed8SAndrew Rybchenko ignore = siena_ev_rx_not_ok(eep, eqp, label, id, &flags); 7435e111ed8SAndrew Rybchenko if (ignore) { 7445e111ed8SAndrew Rybchenko EFSYS_PROBE4(rx_complete, uint32_t, label, uint32_t, id, 7455e111ed8SAndrew Rybchenko uint32_t, size, uint16_t, flags); 7465e111ed8SAndrew Rybchenko 7475e111ed8SAndrew Rybchenko return (B_FALSE); 7485e111ed8SAndrew Rybchenko } 7495e111ed8SAndrew Rybchenko } 7505e111ed8SAndrew Rybchenko 7515e111ed8SAndrew Rybchenko /* If we're not discarding the packet then it is ok */ 7525e111ed8SAndrew Rybchenko if (~flags & EFX_DISCARD) 7535e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_OK); 7545e111ed8SAndrew Rybchenko 7555e111ed8SAndrew Rybchenko /* Detect multicast packets that didn't match the filter */ 7565e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_MCAST_PKT) != 0) { 7575e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_MCAST_PKT); 7585e111ed8SAndrew Rybchenko 7595e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_MCAST_HASH_MATCH) != 0) { 7605e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_RX_MCAST_HASH_MATCH); 7615e111ed8SAndrew Rybchenko } else { 7625e111ed8SAndrew Rybchenko EFSYS_PROBE(mcast_mismatch); 7635e111ed8SAndrew Rybchenko flags |= EFX_ADDR_MISMATCH; 7645e111ed8SAndrew Rybchenko } 7655e111ed8SAndrew Rybchenko } else { 7665e111ed8SAndrew Rybchenko flags |= EFX_PKT_UNICAST; 7675e111ed8SAndrew Rybchenko } 7685e111ed8SAndrew Rybchenko 7695e111ed8SAndrew Rybchenko /* 7705e111ed8SAndrew Rybchenko * The packet parser in Siena can abort parsing packets under 7715e111ed8SAndrew Rybchenko * certain error conditions, setting the PKT_NOT_PARSED bit 7725e111ed8SAndrew Rybchenko * (which clears PKT_OK). If this is set, then don't trust 7735e111ed8SAndrew Rybchenko * the PKT_TYPE field. 7745e111ed8SAndrew Rybchenko */ 7755e111ed8SAndrew Rybchenko if (!ok) { 7765e111ed8SAndrew Rybchenko uint32_t parse_err; 7775e111ed8SAndrew Rybchenko 7785e111ed8SAndrew Rybchenko parse_err = EFX_QWORD_FIELD(*eqp, FSF_CZ_RX_EV_PKT_NOT_PARSED); 7795e111ed8SAndrew Rybchenko if (parse_err != 0) 7805e111ed8SAndrew Rybchenko flags |= EFX_CHECK_VLAN; 7815e111ed8SAndrew Rybchenko } 7825e111ed8SAndrew Rybchenko 7835e111ed8SAndrew Rybchenko if (~flags & EFX_CHECK_VLAN) { 7845e111ed8SAndrew Rybchenko uint32_t pkt_type; 7855e111ed8SAndrew Rybchenko 7865e111ed8SAndrew Rybchenko pkt_type = EFX_QWORD_FIELD(*eqp, FSF_AZ_RX_EV_PKT_TYPE); 7875e111ed8SAndrew Rybchenko if (pkt_type >= FSE_AZ_RX_EV_PKT_TYPE_VLAN) 7885e111ed8SAndrew Rybchenko flags |= EFX_PKT_VLAN_TAGGED; 7895e111ed8SAndrew Rybchenko } 7905e111ed8SAndrew Rybchenko 7915e111ed8SAndrew Rybchenko EFSYS_PROBE4(rx_complete, uint32_t, label, uint32_t, id, 7925e111ed8SAndrew Rybchenko uint32_t, size, uint16_t, flags); 7935e111ed8SAndrew Rybchenko 7945e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_rx != NULL); 7955e111ed8SAndrew Rybchenko should_abort = eecp->eec_rx(arg, label, id, size, flags); 7965e111ed8SAndrew Rybchenko 7975e111ed8SAndrew Rybchenko return (should_abort); 7985e111ed8SAndrew Rybchenko } 7995e111ed8SAndrew Rybchenko 8005e111ed8SAndrew Rybchenko static __checkReturn boolean_t 8015e111ed8SAndrew Rybchenko siena_ev_tx( 8025e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 8035e111ed8SAndrew Rybchenko __in efx_qword_t *eqp, 8045e111ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 8055e111ed8SAndrew Rybchenko __in_opt void *arg) 8065e111ed8SAndrew Rybchenko { 8075e111ed8SAndrew Rybchenko uint32_t id; 8085e111ed8SAndrew Rybchenko uint32_t label; 8095e111ed8SAndrew Rybchenko boolean_t should_abort; 8105e111ed8SAndrew Rybchenko 8115e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_TX); 8125e111ed8SAndrew Rybchenko 8135e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_COMP) != 0 && 8145e111ed8SAndrew Rybchenko EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_ERR) == 0 && 8155e111ed8SAndrew Rybchenko EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_TOO_BIG) == 0 && 8165e111ed8SAndrew Rybchenko EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_WQ_FF_FULL) == 0) { 8175e111ed8SAndrew Rybchenko 8185e111ed8SAndrew Rybchenko id = EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_DESC_PTR); 8195e111ed8SAndrew Rybchenko label = EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_Q_LABEL); 8205e111ed8SAndrew Rybchenko 8215e111ed8SAndrew Rybchenko EFSYS_PROBE2(tx_complete, uint32_t, label, uint32_t, id); 8225e111ed8SAndrew Rybchenko 8235e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_tx != NULL); 8245e111ed8SAndrew Rybchenko should_abort = eecp->eec_tx(arg, label, id); 8255e111ed8SAndrew Rybchenko 8265e111ed8SAndrew Rybchenko return (should_abort); 8275e111ed8SAndrew Rybchenko } 8285e111ed8SAndrew Rybchenko 8295e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_COMP) != 0) 8305e111ed8SAndrew Rybchenko EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, 8315e111ed8SAndrew Rybchenko uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), 8325e111ed8SAndrew Rybchenko uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); 8335e111ed8SAndrew Rybchenko 8345e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_ERR) != 0) 8355e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_TX_PKT_ERR); 8365e111ed8SAndrew Rybchenko 8375e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_PKT_TOO_BIG) != 0) 8385e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_TX_PKT_TOO_BIG); 8395e111ed8SAndrew Rybchenko 8405e111ed8SAndrew Rybchenko if (EFX_QWORD_FIELD(*eqp, FSF_AZ_TX_EV_WQ_FF_FULL) != 0) 8415e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_TX_WQ_FF_FULL); 8425e111ed8SAndrew Rybchenko 8435e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_TX_UNEXPECTED); 8445e111ed8SAndrew Rybchenko return (B_FALSE); 8455e111ed8SAndrew Rybchenko } 8465e111ed8SAndrew Rybchenko 8475e111ed8SAndrew Rybchenko static __checkReturn boolean_t 8485e111ed8SAndrew Rybchenko siena_ev_global( 8495e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 8505e111ed8SAndrew Rybchenko __in efx_qword_t *eqp, 8515e111ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 8525e111ed8SAndrew Rybchenko __in_opt void *arg) 8535e111ed8SAndrew Rybchenko { 8545e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(eqp, eecp, arg)) 8555e111ed8SAndrew Rybchenko 8565e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_GLOBAL); 8575e111ed8SAndrew Rybchenko 8585e111ed8SAndrew Rybchenko return (B_FALSE); 8595e111ed8SAndrew Rybchenko } 8605e111ed8SAndrew Rybchenko 8615e111ed8SAndrew Rybchenko static __checkReturn boolean_t 8625e111ed8SAndrew Rybchenko siena_ev_driver( 8635e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 8645e111ed8SAndrew Rybchenko __in efx_qword_t *eqp, 8655e111ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 8665e111ed8SAndrew Rybchenko __in_opt void *arg) 8675e111ed8SAndrew Rybchenko { 8685e111ed8SAndrew Rybchenko boolean_t should_abort; 8695e111ed8SAndrew Rybchenko 8705e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_DRIVER); 8715e111ed8SAndrew Rybchenko should_abort = B_FALSE; 8725e111ed8SAndrew Rybchenko 8735e111ed8SAndrew Rybchenko switch (EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBCODE)) { 8745e111ed8SAndrew Rybchenko case FSE_AZ_TX_DESCQ_FLS_DONE_EV: { 8755e111ed8SAndrew Rybchenko uint32_t txq_index; 8765e111ed8SAndrew Rybchenko 8775e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DESCQ_FLS_DONE); 8785e111ed8SAndrew Rybchenko 8795e111ed8SAndrew Rybchenko txq_index = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA); 8805e111ed8SAndrew Rybchenko 8815e111ed8SAndrew Rybchenko EFSYS_PROBE1(tx_descq_fls_done, uint32_t, txq_index); 8825e111ed8SAndrew Rybchenko 8835e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_txq_flush_done != NULL); 8845e111ed8SAndrew Rybchenko should_abort = eecp->eec_txq_flush_done(arg, txq_index); 8855e111ed8SAndrew Rybchenko 8865e111ed8SAndrew Rybchenko break; 8875e111ed8SAndrew Rybchenko } 8885e111ed8SAndrew Rybchenko case FSE_AZ_RX_DESCQ_FLS_DONE_EV: { 8895e111ed8SAndrew Rybchenko uint32_t rxq_index; 8905e111ed8SAndrew Rybchenko uint32_t failed; 8915e111ed8SAndrew Rybchenko 8925e111ed8SAndrew Rybchenko rxq_index = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_RX_DESCQ_ID); 8935e111ed8SAndrew Rybchenko failed = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL); 8945e111ed8SAndrew Rybchenko 8955e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_rxq_flush_done != NULL); 8965e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_rxq_flush_failed != NULL); 8975e111ed8SAndrew Rybchenko 8985e111ed8SAndrew Rybchenko if (failed) { 8995e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_FAILED); 9005e111ed8SAndrew Rybchenko 9015e111ed8SAndrew Rybchenko EFSYS_PROBE1(rx_descq_fls_failed, uint32_t, rxq_index); 9025e111ed8SAndrew Rybchenko 9035e111ed8SAndrew Rybchenko should_abort = eecp->eec_rxq_flush_failed(arg, 9045e111ed8SAndrew Rybchenko rxq_index); 9055e111ed8SAndrew Rybchenko } else { 9065e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DESCQ_FLS_DONE); 9075e111ed8SAndrew Rybchenko 9085e111ed8SAndrew Rybchenko EFSYS_PROBE1(rx_descq_fls_done, uint32_t, rxq_index); 9095e111ed8SAndrew Rybchenko 9105e111ed8SAndrew Rybchenko should_abort = eecp->eec_rxq_flush_done(arg, rxq_index); 9115e111ed8SAndrew Rybchenko } 9125e111ed8SAndrew Rybchenko 9135e111ed8SAndrew Rybchenko break; 9145e111ed8SAndrew Rybchenko } 9155e111ed8SAndrew Rybchenko case FSE_AZ_EVQ_INIT_DONE_EV: 9165e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_initialized != NULL); 9175e111ed8SAndrew Rybchenko should_abort = eecp->eec_initialized(arg); 9185e111ed8SAndrew Rybchenko 9195e111ed8SAndrew Rybchenko break; 9205e111ed8SAndrew Rybchenko 9215e111ed8SAndrew Rybchenko case FSE_AZ_EVQ_NOT_EN_EV: 9225e111ed8SAndrew Rybchenko EFSYS_PROBE(evq_not_en); 9235e111ed8SAndrew Rybchenko break; 9245e111ed8SAndrew Rybchenko 9255e111ed8SAndrew Rybchenko case FSE_AZ_SRM_UPD_DONE_EV: { 9265e111ed8SAndrew Rybchenko uint32_t code; 9275e111ed8SAndrew Rybchenko 9285e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_DRIVER_SRM_UPD_DONE); 9295e111ed8SAndrew Rybchenko 9305e111ed8SAndrew Rybchenko code = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA); 9315e111ed8SAndrew Rybchenko 9325e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_sram != NULL); 9335e111ed8SAndrew Rybchenko should_abort = eecp->eec_sram(arg, code); 9345e111ed8SAndrew Rybchenko 9355e111ed8SAndrew Rybchenko break; 9365e111ed8SAndrew Rybchenko } 9375e111ed8SAndrew Rybchenko case FSE_AZ_WAKE_UP_EV: { 9385e111ed8SAndrew Rybchenko uint32_t id; 9395e111ed8SAndrew Rybchenko 9405e111ed8SAndrew Rybchenko id = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA); 9415e111ed8SAndrew Rybchenko 9425e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_wake_up != NULL); 9435e111ed8SAndrew Rybchenko should_abort = eecp->eec_wake_up(arg, id); 9445e111ed8SAndrew Rybchenko 9455e111ed8SAndrew Rybchenko break; 9465e111ed8SAndrew Rybchenko } 9475e111ed8SAndrew Rybchenko case FSE_AZ_TX_PKT_NON_TCP_UDP: 9485e111ed8SAndrew Rybchenko EFSYS_PROBE(tx_pkt_non_tcp_udp); 9495e111ed8SAndrew Rybchenko break; 9505e111ed8SAndrew Rybchenko 9515e111ed8SAndrew Rybchenko case FSE_AZ_TIMER_EV: { 9525e111ed8SAndrew Rybchenko uint32_t id; 9535e111ed8SAndrew Rybchenko 9545e111ed8SAndrew Rybchenko id = EFX_QWORD_FIELD(*eqp, FSF_AZ_DRIVER_EV_SUBDATA); 9555e111ed8SAndrew Rybchenko 9565e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_timer != NULL); 9575e111ed8SAndrew Rybchenko should_abort = eecp->eec_timer(arg, id); 9585e111ed8SAndrew Rybchenko 9595e111ed8SAndrew Rybchenko break; 9605e111ed8SAndrew Rybchenko } 9615e111ed8SAndrew Rybchenko case FSE_AZ_RX_DSC_ERROR_EV: 9625e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_DRIVER_RX_DSC_ERROR); 9635e111ed8SAndrew Rybchenko 9645e111ed8SAndrew Rybchenko EFSYS_PROBE(rx_dsc_error); 9655e111ed8SAndrew Rybchenko 9665e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_exception != NULL); 9675e111ed8SAndrew Rybchenko should_abort = eecp->eec_exception(arg, 9685e111ed8SAndrew Rybchenko EFX_EXCEPTION_RX_DSC_ERROR, 0); 9695e111ed8SAndrew Rybchenko 9705e111ed8SAndrew Rybchenko break; 9715e111ed8SAndrew Rybchenko 9725e111ed8SAndrew Rybchenko case FSE_AZ_TX_DSC_ERROR_EV: 9735e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_DRIVER_TX_DSC_ERROR); 9745e111ed8SAndrew Rybchenko 9755e111ed8SAndrew Rybchenko EFSYS_PROBE(tx_dsc_error); 9765e111ed8SAndrew Rybchenko 9775e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_exception != NULL); 9785e111ed8SAndrew Rybchenko should_abort = eecp->eec_exception(arg, 9795e111ed8SAndrew Rybchenko EFX_EXCEPTION_TX_DSC_ERROR, 0); 9805e111ed8SAndrew Rybchenko 9815e111ed8SAndrew Rybchenko break; 9825e111ed8SAndrew Rybchenko 9835e111ed8SAndrew Rybchenko default: 9845e111ed8SAndrew Rybchenko break; 9855e111ed8SAndrew Rybchenko } 9865e111ed8SAndrew Rybchenko 9875e111ed8SAndrew Rybchenko return (should_abort); 9885e111ed8SAndrew Rybchenko } 9895e111ed8SAndrew Rybchenko 9905e111ed8SAndrew Rybchenko static __checkReturn boolean_t 9915e111ed8SAndrew Rybchenko siena_ev_drv_gen( 9925e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 9935e111ed8SAndrew Rybchenko __in efx_qword_t *eqp, 9945e111ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 9955e111ed8SAndrew Rybchenko __in_opt void *arg) 9965e111ed8SAndrew Rybchenko { 9975e111ed8SAndrew Rybchenko uint32_t data; 9985e111ed8SAndrew Rybchenko boolean_t should_abort; 9995e111ed8SAndrew Rybchenko 10005e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_DRV_GEN); 10015e111ed8SAndrew Rybchenko 10025e111ed8SAndrew Rybchenko data = EFX_QWORD_FIELD(*eqp, FSF_AZ_EV_DATA_DW0); 10035e111ed8SAndrew Rybchenko if (data >= ((uint32_t)1 << 16)) { 10045e111ed8SAndrew Rybchenko EFSYS_PROBE3(bad_event, unsigned int, eep->ee_index, 10055e111ed8SAndrew Rybchenko uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_1), 10065e111ed8SAndrew Rybchenko uint32_t, EFX_QWORD_FIELD(*eqp, EFX_DWORD_0)); 10075e111ed8SAndrew Rybchenko return (B_TRUE); 10085e111ed8SAndrew Rybchenko } 10095e111ed8SAndrew Rybchenko 10105e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_software != NULL); 10115e111ed8SAndrew Rybchenko should_abort = eecp->eec_software(arg, (uint16_t)data); 10125e111ed8SAndrew Rybchenko 10135e111ed8SAndrew Rybchenko return (should_abort); 10145e111ed8SAndrew Rybchenko } 10155e111ed8SAndrew Rybchenko 10165e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI 10175e111ed8SAndrew Rybchenko 10185e111ed8SAndrew Rybchenko static __checkReturn boolean_t 10195e111ed8SAndrew Rybchenko siena_ev_mcdi( 10205e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 10215e111ed8SAndrew Rybchenko __in efx_qword_t *eqp, 10225e111ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 10235e111ed8SAndrew Rybchenko __in_opt void *arg) 10245e111ed8SAndrew Rybchenko { 10255e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 10265e111ed8SAndrew Rybchenko unsigned int code; 10275e111ed8SAndrew Rybchenko boolean_t should_abort = B_FALSE; 10285e111ed8SAndrew Rybchenko 10295e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 10305e111ed8SAndrew Rybchenko 10315e111ed8SAndrew Rybchenko if (enp->en_family != EFX_FAMILY_SIENA) 10325e111ed8SAndrew Rybchenko goto out; 10335e111ed8SAndrew Rybchenko 10345e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_link_change != NULL); 10355e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_exception != NULL); 10365e111ed8SAndrew Rybchenko #if EFSYS_OPT_MON_STATS 10375e111ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_monitor != NULL); 10385e111ed8SAndrew Rybchenko #endif 10395e111ed8SAndrew Rybchenko 10405e111ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_MCDI_RESPONSE); 10415e111ed8SAndrew Rybchenko 10425e111ed8SAndrew Rybchenko code = EFX_QWORD_FIELD(*eqp, MCDI_EVENT_CODE); 10435e111ed8SAndrew Rybchenko switch (code) { 10445e111ed8SAndrew Rybchenko case MCDI_EVENT_CODE_BADSSERT: 10455e111ed8SAndrew Rybchenko efx_mcdi_ev_death(enp, EINTR); 10465e111ed8SAndrew Rybchenko break; 10475e111ed8SAndrew Rybchenko 10485e111ed8SAndrew Rybchenko case MCDI_EVENT_CODE_CMDDONE: 10495e111ed8SAndrew Rybchenko efx_mcdi_ev_cpl(enp, 10505e111ed8SAndrew Rybchenko MCDI_EV_FIELD(eqp, CMDDONE_SEQ), 10515e111ed8SAndrew Rybchenko MCDI_EV_FIELD(eqp, CMDDONE_DATALEN), 10525e111ed8SAndrew Rybchenko MCDI_EV_FIELD(eqp, CMDDONE_ERRNO)); 10535e111ed8SAndrew Rybchenko break; 10545e111ed8SAndrew Rybchenko 10555e111ed8SAndrew Rybchenko case MCDI_EVENT_CODE_LINKCHANGE: { 10565e111ed8SAndrew Rybchenko efx_link_mode_t link_mode; 10575e111ed8SAndrew Rybchenko 10585e111ed8SAndrew Rybchenko siena_phy_link_ev(enp, eqp, &link_mode); 10595e111ed8SAndrew Rybchenko should_abort = eecp->eec_link_change(arg, link_mode); 10605e111ed8SAndrew Rybchenko break; 10615e111ed8SAndrew Rybchenko } 10625e111ed8SAndrew Rybchenko case MCDI_EVENT_CODE_SENSOREVT: { 10635e111ed8SAndrew Rybchenko #if EFSYS_OPT_MON_STATS 10645e111ed8SAndrew Rybchenko efx_mon_stat_t id; 10655e111ed8SAndrew Rybchenko efx_mon_stat_value_t value; 10665e111ed8SAndrew Rybchenko efx_rc_t rc; 10675e111ed8SAndrew Rybchenko 10685e111ed8SAndrew Rybchenko if ((rc = mcdi_mon_ev(enp, eqp, &id, &value)) == 0) 10695e111ed8SAndrew Rybchenko should_abort = eecp->eec_monitor(arg, id, value); 10705e111ed8SAndrew Rybchenko else if (rc == ENOTSUP) { 10715e111ed8SAndrew Rybchenko should_abort = eecp->eec_exception(arg, 10725e111ed8SAndrew Rybchenko EFX_EXCEPTION_UNKNOWN_SENSOREVT, 10735e111ed8SAndrew Rybchenko MCDI_EV_FIELD(eqp, DATA)); 10745e111ed8SAndrew Rybchenko } else 10755e111ed8SAndrew Rybchenko EFSYS_ASSERT(rc == ENODEV); /* Wrong port */ 10765e111ed8SAndrew Rybchenko #else 10775e111ed8SAndrew Rybchenko should_abort = B_FALSE; 10785e111ed8SAndrew Rybchenko #endif 10795e111ed8SAndrew Rybchenko break; 10805e111ed8SAndrew Rybchenko } 10815e111ed8SAndrew Rybchenko case MCDI_EVENT_CODE_SCHEDERR: 10825e111ed8SAndrew Rybchenko /* Informational only */ 10835e111ed8SAndrew Rybchenko break; 10845e111ed8SAndrew Rybchenko 10855e111ed8SAndrew Rybchenko case MCDI_EVENT_CODE_REBOOT: 10865e111ed8SAndrew Rybchenko efx_mcdi_ev_death(enp, EIO); 10875e111ed8SAndrew Rybchenko break; 10885e111ed8SAndrew Rybchenko 10895e111ed8SAndrew Rybchenko case MCDI_EVENT_CODE_MAC_STATS_DMA: 10905e111ed8SAndrew Rybchenko #if EFSYS_OPT_MAC_STATS 10915e111ed8SAndrew Rybchenko if (eecp->eec_mac_stats != NULL) { 10925e111ed8SAndrew Rybchenko eecp->eec_mac_stats(arg, 10935e111ed8SAndrew Rybchenko MCDI_EV_FIELD(eqp, MAC_STATS_DMA_GENERATION)); 10945e111ed8SAndrew Rybchenko } 10955e111ed8SAndrew Rybchenko #endif 10965e111ed8SAndrew Rybchenko break; 10975e111ed8SAndrew Rybchenko 10985e111ed8SAndrew Rybchenko case MCDI_EVENT_CODE_FWALERT: { 10995e111ed8SAndrew Rybchenko uint32_t reason = MCDI_EV_FIELD(eqp, FWALERT_REASON); 11005e111ed8SAndrew Rybchenko 11015e111ed8SAndrew Rybchenko if (reason == MCDI_EVENT_FWALERT_REASON_SRAM_ACCESS) 11025e111ed8SAndrew Rybchenko should_abort = eecp->eec_exception(arg, 11035e111ed8SAndrew Rybchenko EFX_EXCEPTION_FWALERT_SRAM, 11045e111ed8SAndrew Rybchenko MCDI_EV_FIELD(eqp, FWALERT_DATA)); 11055e111ed8SAndrew Rybchenko else 11065e111ed8SAndrew Rybchenko should_abort = eecp->eec_exception(arg, 11075e111ed8SAndrew Rybchenko EFX_EXCEPTION_UNKNOWN_FWALERT, 11085e111ed8SAndrew Rybchenko MCDI_EV_FIELD(eqp, DATA)); 11095e111ed8SAndrew Rybchenko break; 11105e111ed8SAndrew Rybchenko } 11115e111ed8SAndrew Rybchenko 11125e111ed8SAndrew Rybchenko default: 11135e111ed8SAndrew Rybchenko EFSYS_PROBE1(mc_pcol_error, int, code); 11145e111ed8SAndrew Rybchenko break; 11155e111ed8SAndrew Rybchenko } 11165e111ed8SAndrew Rybchenko 11175e111ed8SAndrew Rybchenko out: 11185e111ed8SAndrew Rybchenko return (should_abort); 11195e111ed8SAndrew Rybchenko } 11205e111ed8SAndrew Rybchenko 11215e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI */ 11225e111ed8SAndrew Rybchenko 11235e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 11245e111ed8SAndrew Rybchenko siena_ev_qprime( 11255e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 11265e111ed8SAndrew Rybchenko __in unsigned int count) 11275e111ed8SAndrew Rybchenko { 11285e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 11295e111ed8SAndrew Rybchenko uint32_t rptr; 11305e111ed8SAndrew Rybchenko efx_dword_t dword; 11315e111ed8SAndrew Rybchenko 11325e111ed8SAndrew Rybchenko rptr = count & eep->ee_mask; 11335e111ed8SAndrew Rybchenko 11345e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_1(dword, FRF_AZ_EVQ_RPTR, rptr); 11355e111ed8SAndrew Rybchenko 11365e111ed8SAndrew Rybchenko EFX_BAR_TBL_WRITED(enp, FR_AZ_EVQ_RPTR_REG, eep->ee_index, 11375e111ed8SAndrew Rybchenko &dword, B_FALSE); 11385e111ed8SAndrew Rybchenko 11395e111ed8SAndrew Rybchenko return (0); 11405e111ed8SAndrew Rybchenko } 11415e111ed8SAndrew Rybchenko 11425e111ed8SAndrew Rybchenko static void 11435e111ed8SAndrew Rybchenko siena_ev_qpost( 11445e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 11455e111ed8SAndrew Rybchenko __in uint16_t data) 11465e111ed8SAndrew Rybchenko { 11475e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 11485e111ed8SAndrew Rybchenko efx_qword_t ev; 11495e111ed8SAndrew Rybchenko efx_oword_t oword; 11505e111ed8SAndrew Rybchenko 11515e111ed8SAndrew Rybchenko EFX_POPULATE_QWORD_2(ev, FSF_AZ_EV_CODE, FSE_AZ_EV_CODE_DRV_GEN_EV, 11525e111ed8SAndrew Rybchenko FSF_AZ_EV_DATA_DW0, (uint32_t)data); 11535e111ed8SAndrew Rybchenko 11545e111ed8SAndrew Rybchenko EFX_POPULATE_OWORD_3(oword, FRF_AZ_DRV_EV_QID, eep->ee_index, 11555e111ed8SAndrew Rybchenko EFX_DWORD_0, EFX_QWORD_FIELD(ev, EFX_DWORD_0), 11565e111ed8SAndrew Rybchenko EFX_DWORD_1, EFX_QWORD_FIELD(ev, EFX_DWORD_1)); 11575e111ed8SAndrew Rybchenko 11585e111ed8SAndrew Rybchenko EFX_BAR_WRITEO(enp, FR_AZ_DRV_EV_REG, &oword); 11595e111ed8SAndrew Rybchenko } 11605e111ed8SAndrew Rybchenko 11615e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 11625e111ed8SAndrew Rybchenko siena_ev_qmoderate( 11635e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 11645e111ed8SAndrew Rybchenko __in unsigned int us) 11655e111ed8SAndrew Rybchenko { 11665e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 11675e111ed8SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 11685e111ed8SAndrew Rybchenko unsigned int locked; 11695e111ed8SAndrew Rybchenko efx_dword_t dword; 11705e111ed8SAndrew Rybchenko efx_rc_t rc; 11715e111ed8SAndrew Rybchenko 11725e111ed8SAndrew Rybchenko if (us > encp->enc_evq_timer_max_us) { 11735e111ed8SAndrew Rybchenko rc = EINVAL; 11745e111ed8SAndrew Rybchenko goto fail1; 11755e111ed8SAndrew Rybchenko } 11765e111ed8SAndrew Rybchenko 11775e111ed8SAndrew Rybchenko /* If the value is zero then disable the timer */ 11785e111ed8SAndrew Rybchenko if (us == 0) { 11795e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_2(dword, 11805e111ed8SAndrew Rybchenko FRF_CZ_TC_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS, 11815e111ed8SAndrew Rybchenko FRF_CZ_TC_TIMER_VAL, 0); 11825e111ed8SAndrew Rybchenko } else { 11835e111ed8SAndrew Rybchenko unsigned int ticks; 11845e111ed8SAndrew Rybchenko 11855e111ed8SAndrew Rybchenko if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0) 11865e111ed8SAndrew Rybchenko goto fail2; 11875e111ed8SAndrew Rybchenko 11885e111ed8SAndrew Rybchenko EFSYS_ASSERT(ticks > 0); 11895e111ed8SAndrew Rybchenko EFX_POPULATE_DWORD_2(dword, 11905e111ed8SAndrew Rybchenko FRF_CZ_TC_TIMER_MODE, FFE_CZ_TIMER_MODE_INT_HLDOFF, 11915e111ed8SAndrew Rybchenko FRF_CZ_TC_TIMER_VAL, ticks - 1); 11925e111ed8SAndrew Rybchenko } 11935e111ed8SAndrew Rybchenko 11945e111ed8SAndrew Rybchenko locked = (eep->ee_index == 0) ? 1 : 0; 11955e111ed8SAndrew Rybchenko 11965e111ed8SAndrew Rybchenko EFX_BAR_TBL_WRITED(enp, FR_BZ_TIMER_COMMAND_REGP0, 11975e111ed8SAndrew Rybchenko eep->ee_index, &dword, locked); 11985e111ed8SAndrew Rybchenko 11995e111ed8SAndrew Rybchenko return (0); 12005e111ed8SAndrew Rybchenko 12015e111ed8SAndrew Rybchenko fail2: 12025e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 12035e111ed8SAndrew Rybchenko fail1: 12045e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 12055e111ed8SAndrew Rybchenko 12065e111ed8SAndrew Rybchenko return (rc); 12075e111ed8SAndrew Rybchenko } 12085e111ed8SAndrew Rybchenko 12095e111ed8SAndrew Rybchenko static __checkReturn efx_rc_t 12105e111ed8SAndrew Rybchenko siena_ev_qcreate( 12115e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 12125e111ed8SAndrew Rybchenko __in unsigned int index, 12135e111ed8SAndrew Rybchenko __in efsys_mem_t *esmp, 12145e111ed8SAndrew Rybchenko __in size_t ndescs, 12155e111ed8SAndrew Rybchenko __in uint32_t id, 12165e111ed8SAndrew Rybchenko __in uint32_t us, 12175e111ed8SAndrew Rybchenko __in uint32_t flags, 12185e111ed8SAndrew Rybchenko __in efx_evq_t *eep) 12195e111ed8SAndrew Rybchenko { 12205e111ed8SAndrew Rybchenko efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 12215e111ed8SAndrew Rybchenko uint32_t size; 12225e111ed8SAndrew Rybchenko efx_oword_t oword; 12235e111ed8SAndrew Rybchenko efx_rc_t rc; 12245e111ed8SAndrew Rybchenko boolean_t notify_mode; 12255e111ed8SAndrew Rybchenko 12265e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(esmp)) 12275e111ed8SAndrew Rybchenko 12285e111ed8SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE 12295e111ed8SAndrew Rybchenko if (enp->en_intr.ei_type == EFX_INTR_LINE && 12305e111ed8SAndrew Rybchenko index >= EFX_MAXRSS_LEGACY) { 12315e111ed8SAndrew Rybchenko rc = EINVAL; 12322e5819a5SAndrew Rybchenko goto fail1; 12335e111ed8SAndrew Rybchenko } 12345e111ed8SAndrew Rybchenko #endif 12355e111ed8SAndrew Rybchenko for (size = 0; 12365e111ed8SAndrew Rybchenko (1U << size) <= encp->enc_evq_max_nevs / encp->enc_evq_min_nevs; 12375e111ed8SAndrew Rybchenko size++) 12385e111ed8SAndrew Rybchenko if ((1U << size) == (uint32_t)ndescs / encp->enc_evq_min_nevs) 12395e111ed8SAndrew Rybchenko break; 12405e111ed8SAndrew Rybchenko if (id + (1 << size) >= encp->enc_buftbl_limit) { 12415e111ed8SAndrew Rybchenko rc = EINVAL; 12422e5819a5SAndrew Rybchenko goto fail2; 12435e111ed8SAndrew Rybchenko } 12445e111ed8SAndrew Rybchenko 12455e111ed8SAndrew Rybchenko /* Set up the handler table */ 12465e111ed8SAndrew Rybchenko eep->ee_rx = siena_ev_rx; 12475e111ed8SAndrew Rybchenko eep->ee_tx = siena_ev_tx; 12485e111ed8SAndrew Rybchenko eep->ee_driver = siena_ev_driver; 12495e111ed8SAndrew Rybchenko eep->ee_global = siena_ev_global; 12505e111ed8SAndrew Rybchenko eep->ee_drv_gen = siena_ev_drv_gen; 12515e111ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI 12525e111ed8SAndrew Rybchenko eep->ee_mcdi = siena_ev_mcdi; 12535e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_MCDI */ 12545e111ed8SAndrew Rybchenko 12555e111ed8SAndrew Rybchenko notify_mode = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) != 12565e111ed8SAndrew Rybchenko EFX_EVQ_FLAGS_NOTIFY_INTERRUPT); 12575e111ed8SAndrew Rybchenko 12585e111ed8SAndrew Rybchenko /* Set up the new event queue */ 12595e111ed8SAndrew Rybchenko EFX_POPULATE_OWORD_3(oword, FRF_CZ_TIMER_Q_EN, 1, 12605e111ed8SAndrew Rybchenko FRF_CZ_HOST_NOTIFY_MODE, notify_mode, 12615e111ed8SAndrew Rybchenko FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS); 12625e111ed8SAndrew Rybchenko EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL, index, &oword, B_TRUE); 12635e111ed8SAndrew Rybchenko 12645e111ed8SAndrew Rybchenko EFX_POPULATE_OWORD_3(oword, FRF_AZ_EVQ_EN, 1, FRF_AZ_EVQ_SIZE, size, 12655e111ed8SAndrew Rybchenko FRF_AZ_EVQ_BUF_BASE_ID, id); 12665e111ed8SAndrew Rybchenko 12675e111ed8SAndrew Rybchenko EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL, index, &oword, B_TRUE); 12685e111ed8SAndrew Rybchenko 12695e111ed8SAndrew Rybchenko /* Set initial interrupt moderation */ 12705e111ed8SAndrew Rybchenko siena_ev_qmoderate(eep, us); 12715e111ed8SAndrew Rybchenko 12725e111ed8SAndrew Rybchenko return (0); 12735e111ed8SAndrew Rybchenko 12745e111ed8SAndrew Rybchenko fail2: 12755e111ed8SAndrew Rybchenko EFSYS_PROBE(fail2); 12762e5819a5SAndrew Rybchenko #if EFSYS_OPT_RX_SCALE 12775e111ed8SAndrew Rybchenko fail1: 12782e5819a5SAndrew Rybchenko #endif 12795e111ed8SAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 12805e111ed8SAndrew Rybchenko 12815e111ed8SAndrew Rybchenko return (rc); 12825e111ed8SAndrew Rybchenko } 12835e111ed8SAndrew Rybchenko 12845e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */ 12855e111ed8SAndrew Rybchenko 12865e111ed8SAndrew Rybchenko #if EFSYS_OPT_QSTATS 12875e111ed8SAndrew Rybchenko #if EFSYS_OPT_NAMES 12885e111ed8SAndrew Rybchenko /* START MKCONFIG GENERATED EfxEventQueueStatNamesBlock ac223f7134058b4f */ 12895e111ed8SAndrew Rybchenko static const char * const __efx_ev_qstat_name[] = { 12905e111ed8SAndrew Rybchenko "all", 12915e111ed8SAndrew Rybchenko "rx", 12925e111ed8SAndrew Rybchenko "rx_ok", 12935e111ed8SAndrew Rybchenko "rx_frm_trunc", 12945e111ed8SAndrew Rybchenko "rx_tobe_disc", 12955e111ed8SAndrew Rybchenko "rx_pause_frm_err", 12965e111ed8SAndrew Rybchenko "rx_buf_owner_id_err", 12975e111ed8SAndrew Rybchenko "rx_ipv4_hdr_chksum_err", 12985e111ed8SAndrew Rybchenko "rx_tcp_udp_chksum_err", 12995e111ed8SAndrew Rybchenko "rx_eth_crc_err", 13005e111ed8SAndrew Rybchenko "rx_ip_frag_err", 13015e111ed8SAndrew Rybchenko "rx_mcast_pkt", 13025e111ed8SAndrew Rybchenko "rx_mcast_hash_match", 13035e111ed8SAndrew Rybchenko "rx_tcp_ipv4", 13045e111ed8SAndrew Rybchenko "rx_tcp_ipv6", 13055e111ed8SAndrew Rybchenko "rx_udp_ipv4", 13065e111ed8SAndrew Rybchenko "rx_udp_ipv6", 13075e111ed8SAndrew Rybchenko "rx_other_ipv4", 13085e111ed8SAndrew Rybchenko "rx_other_ipv6", 13095e111ed8SAndrew Rybchenko "rx_non_ip", 13105e111ed8SAndrew Rybchenko "rx_batch", 13115e111ed8SAndrew Rybchenko "tx", 13125e111ed8SAndrew Rybchenko "tx_wq_ff_full", 13135e111ed8SAndrew Rybchenko "tx_pkt_err", 13145e111ed8SAndrew Rybchenko "tx_pkt_too_big", 13155e111ed8SAndrew Rybchenko "tx_unexpected", 13165e111ed8SAndrew Rybchenko "global", 13175e111ed8SAndrew Rybchenko "global_mnt", 13185e111ed8SAndrew Rybchenko "driver", 13195e111ed8SAndrew Rybchenko "driver_srm_upd_done", 13205e111ed8SAndrew Rybchenko "driver_tx_descq_fls_done", 13215e111ed8SAndrew Rybchenko "driver_rx_descq_fls_done", 13225e111ed8SAndrew Rybchenko "driver_rx_descq_fls_failed", 13235e111ed8SAndrew Rybchenko "driver_rx_dsc_error", 13245e111ed8SAndrew Rybchenko "driver_tx_dsc_error", 13255e111ed8SAndrew Rybchenko "drv_gen", 13265e111ed8SAndrew Rybchenko "mcdi_response", 13275e111ed8SAndrew Rybchenko "rx_parse_incomplete", 13285e111ed8SAndrew Rybchenko }; 13295e111ed8SAndrew Rybchenko /* END MKCONFIG GENERATED EfxEventQueueStatNamesBlock */ 13305e111ed8SAndrew Rybchenko 13315e111ed8SAndrew Rybchenko const char * 13325e111ed8SAndrew Rybchenko efx_ev_qstat_name( 13335e111ed8SAndrew Rybchenko __in efx_nic_t *enp, 13345e111ed8SAndrew Rybchenko __in unsigned int id) 13355e111ed8SAndrew Rybchenko { 13365e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(enp)) 13375e111ed8SAndrew Rybchenko 13385e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 13395e111ed8SAndrew Rybchenko EFSYS_ASSERT3U(id, <, EV_NQSTATS); 13405e111ed8SAndrew Rybchenko 13415e111ed8SAndrew Rybchenko return (__efx_ev_qstat_name[id]); 13425e111ed8SAndrew Rybchenko } 13435e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_NAMES */ 13445e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_QSTATS */ 13455e111ed8SAndrew Rybchenko 13465e111ed8SAndrew Rybchenko #if EFSYS_OPT_SIENA 13475e111ed8SAndrew Rybchenko 13485e111ed8SAndrew Rybchenko #if EFSYS_OPT_QSTATS 13495e111ed8SAndrew Rybchenko static void 13505e111ed8SAndrew Rybchenko siena_ev_qstats_update( 13515e111ed8SAndrew Rybchenko __in efx_evq_t *eep, 13525e111ed8SAndrew Rybchenko __inout_ecount(EV_NQSTATS) efsys_stat_t *stat) 13535e111ed8SAndrew Rybchenko { 13545e111ed8SAndrew Rybchenko unsigned int id; 13555e111ed8SAndrew Rybchenko 13565e111ed8SAndrew Rybchenko for (id = 0; id < EV_NQSTATS; id++) { 13575e111ed8SAndrew Rybchenko efsys_stat_t *essp = &stat[id]; 13585e111ed8SAndrew Rybchenko 13595e111ed8SAndrew Rybchenko EFSYS_STAT_INCR(essp, eep->ee_stat[id]); 13605e111ed8SAndrew Rybchenko eep->ee_stat[id] = 0; 13615e111ed8SAndrew Rybchenko } 13625e111ed8SAndrew Rybchenko } 13635e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_QSTATS */ 13645e111ed8SAndrew Rybchenko 13655e111ed8SAndrew Rybchenko static void 13665e111ed8SAndrew Rybchenko siena_ev_qdestroy( 13675e111ed8SAndrew Rybchenko __in efx_evq_t *eep) 13685e111ed8SAndrew Rybchenko { 13695e111ed8SAndrew Rybchenko efx_nic_t *enp = eep->ee_enp; 13705e111ed8SAndrew Rybchenko efx_oword_t oword; 13715e111ed8SAndrew Rybchenko 13725e111ed8SAndrew Rybchenko /* Purge event queue */ 13735e111ed8SAndrew Rybchenko EFX_ZERO_OWORD(oword); 13745e111ed8SAndrew Rybchenko 13755e111ed8SAndrew Rybchenko EFX_BAR_TBL_WRITEO(enp, FR_AZ_EVQ_PTR_TBL, 13765e111ed8SAndrew Rybchenko eep->ee_index, &oword, B_TRUE); 13775e111ed8SAndrew Rybchenko 13785e111ed8SAndrew Rybchenko EFX_ZERO_OWORD(oword); 13795e111ed8SAndrew Rybchenko EFX_BAR_TBL_WRITEO(enp, FR_AZ_TIMER_TBL, eep->ee_index, &oword, B_TRUE); 13805e111ed8SAndrew Rybchenko } 13815e111ed8SAndrew Rybchenko 13825e111ed8SAndrew Rybchenko static void 13835e111ed8SAndrew Rybchenko siena_ev_fini( 13845e111ed8SAndrew Rybchenko __in efx_nic_t *enp) 13855e111ed8SAndrew Rybchenko { 13865e111ed8SAndrew Rybchenko _NOTE(ARGUNUSED(enp)) 13875e111ed8SAndrew Rybchenko } 13885e111ed8SAndrew Rybchenko 13895e111ed8SAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */ 1390ad1e3ed8SAndrew Rybchenko 1391ad1e3ed8SAndrew Rybchenko #if EFX_OPTS_EF10() || EFSYS_OPT_SIENA 1392ad1e3ed8SAndrew Rybchenko 1393ad1e3ed8SAndrew Rybchenko #define EFX_EV_BATCH 8 1394ad1e3ed8SAndrew Rybchenko 1395ad1e3ed8SAndrew Rybchenko static void 1396ad1e3ed8SAndrew Rybchenko siena_ef10_ev_qpoll( 1397ad1e3ed8SAndrew Rybchenko __in efx_evq_t *eep, 1398ad1e3ed8SAndrew Rybchenko __inout unsigned int *countp, 1399ad1e3ed8SAndrew Rybchenko __in const efx_ev_callbacks_t *eecp, 1400ad1e3ed8SAndrew Rybchenko __in_opt void *arg) 1401ad1e3ed8SAndrew Rybchenko { 1402ad1e3ed8SAndrew Rybchenko efx_qword_t ev[EFX_EV_BATCH]; 1403ad1e3ed8SAndrew Rybchenko unsigned int batch; 1404ad1e3ed8SAndrew Rybchenko unsigned int total; 1405ad1e3ed8SAndrew Rybchenko unsigned int count; 1406ad1e3ed8SAndrew Rybchenko unsigned int index; 1407ad1e3ed8SAndrew Rybchenko size_t offset; 1408ad1e3ed8SAndrew Rybchenko 1409ad1e3ed8SAndrew Rybchenko /* Ensure events codes match for EF10 (Huntington/Medford) and Siena */ 1410ad1e3ed8SAndrew Rybchenko EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_LBN == FSF_AZ_EV_CODE_LBN); 1411ad1e3ed8SAndrew Rybchenko EFX_STATIC_ASSERT(ESF_DZ_EV_CODE_WIDTH == FSF_AZ_EV_CODE_WIDTH); 1412ad1e3ed8SAndrew Rybchenko 1413ad1e3ed8SAndrew Rybchenko EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_RX_EV == FSE_AZ_EV_CODE_RX_EV); 1414ad1e3ed8SAndrew Rybchenko EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_TX_EV == FSE_AZ_EV_CODE_TX_EV); 1415ad1e3ed8SAndrew Rybchenko EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRIVER_EV == FSE_AZ_EV_CODE_DRIVER_EV); 1416ad1e3ed8SAndrew Rybchenko EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_DRV_GEN_EV == 1417ad1e3ed8SAndrew Rybchenko FSE_AZ_EV_CODE_DRV_GEN_EV); 1418ad1e3ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI 1419ad1e3ed8SAndrew Rybchenko EFX_STATIC_ASSERT(ESE_DZ_EV_CODE_MCDI_EV == 1420ad1e3ed8SAndrew Rybchenko FSE_AZ_EV_CODE_MCDI_EVRESPONSE); 1421ad1e3ed8SAndrew Rybchenko #endif 1422ad1e3ed8SAndrew Rybchenko 1423ad1e3ed8SAndrew Rybchenko EFSYS_ASSERT3U(eep->ee_magic, ==, EFX_EVQ_MAGIC); 1424ad1e3ed8SAndrew Rybchenko EFSYS_ASSERT(countp != NULL); 1425ad1e3ed8SAndrew Rybchenko EFSYS_ASSERT(eecp != NULL); 1426ad1e3ed8SAndrew Rybchenko 1427ad1e3ed8SAndrew Rybchenko count = *countp; 1428ad1e3ed8SAndrew Rybchenko do { 1429ad1e3ed8SAndrew Rybchenko /* Read up until the end of the batch period */ 1430ad1e3ed8SAndrew Rybchenko batch = EFX_EV_BATCH - (count & (EFX_EV_BATCH - 1)); 1431ad1e3ed8SAndrew Rybchenko offset = (count & eep->ee_mask) * sizeof (efx_qword_t); 1432ad1e3ed8SAndrew Rybchenko for (total = 0; total < batch; ++total) { 1433ad1e3ed8SAndrew Rybchenko EFSYS_MEM_READQ(eep->ee_esmp, offset, &(ev[total])); 1434ad1e3ed8SAndrew Rybchenko 1435ad1e3ed8SAndrew Rybchenko if (!EFX_EV_PRESENT(ev[total])) 1436ad1e3ed8SAndrew Rybchenko break; 1437ad1e3ed8SAndrew Rybchenko 1438ad1e3ed8SAndrew Rybchenko EFSYS_PROBE3(event, unsigned int, eep->ee_index, 1439ad1e3ed8SAndrew Rybchenko uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_1), 1440ad1e3ed8SAndrew Rybchenko uint32_t, EFX_QWORD_FIELD(ev[total], EFX_DWORD_0)); 1441ad1e3ed8SAndrew Rybchenko 1442ad1e3ed8SAndrew Rybchenko offset += sizeof (efx_qword_t); 1443ad1e3ed8SAndrew Rybchenko } 1444ad1e3ed8SAndrew Rybchenko 1445ad1e3ed8SAndrew Rybchenko #if EFSYS_OPT_EV_PREFETCH && (EFSYS_OPT_EV_PREFETCH_PERIOD > 1) 1446ad1e3ed8SAndrew Rybchenko /* 1447ad1e3ed8SAndrew Rybchenko * Prefetch the next batch when we get within PREFETCH_PERIOD 1448ad1e3ed8SAndrew Rybchenko * of a completed batch. If the batch is smaller, then prefetch 1449ad1e3ed8SAndrew Rybchenko * immediately. 1450ad1e3ed8SAndrew Rybchenko */ 1451ad1e3ed8SAndrew Rybchenko if (total == batch && total < EFSYS_OPT_EV_PREFETCH_PERIOD) 1452ad1e3ed8SAndrew Rybchenko EFSYS_MEM_PREFETCH(eep->ee_esmp, offset); 1453ad1e3ed8SAndrew Rybchenko #endif /* EFSYS_OPT_EV_PREFETCH */ 1454ad1e3ed8SAndrew Rybchenko 1455ad1e3ed8SAndrew Rybchenko /* Process the batch of events */ 1456ad1e3ed8SAndrew Rybchenko for (index = 0; index < total; ++index) { 1457ad1e3ed8SAndrew Rybchenko boolean_t should_abort; 1458ad1e3ed8SAndrew Rybchenko uint32_t code; 1459ad1e3ed8SAndrew Rybchenko 1460ad1e3ed8SAndrew Rybchenko #if EFSYS_OPT_EV_PREFETCH 1461ad1e3ed8SAndrew Rybchenko /* Prefetch if we've now reached the batch period */ 1462ad1e3ed8SAndrew Rybchenko if (total == batch && 1463ad1e3ed8SAndrew Rybchenko index + EFSYS_OPT_EV_PREFETCH_PERIOD == total) { 1464ad1e3ed8SAndrew Rybchenko offset = (count + batch) & eep->ee_mask; 1465ad1e3ed8SAndrew Rybchenko offset *= sizeof (efx_qword_t); 1466ad1e3ed8SAndrew Rybchenko 1467ad1e3ed8SAndrew Rybchenko EFSYS_MEM_PREFETCH(eep->ee_esmp, offset); 1468ad1e3ed8SAndrew Rybchenko } 1469ad1e3ed8SAndrew Rybchenko #endif /* EFSYS_OPT_EV_PREFETCH */ 1470ad1e3ed8SAndrew Rybchenko 1471ad1e3ed8SAndrew Rybchenko EFX_EV_QSTAT_INCR(eep, EV_ALL); 1472ad1e3ed8SAndrew Rybchenko 1473ad1e3ed8SAndrew Rybchenko code = EFX_QWORD_FIELD(ev[index], FSF_AZ_EV_CODE); 1474ad1e3ed8SAndrew Rybchenko switch (code) { 1475ad1e3ed8SAndrew Rybchenko case FSE_AZ_EV_CODE_RX_EV: 1476ad1e3ed8SAndrew Rybchenko should_abort = eep->ee_rx(eep, 1477ad1e3ed8SAndrew Rybchenko &(ev[index]), eecp, arg); 1478ad1e3ed8SAndrew Rybchenko break; 1479ad1e3ed8SAndrew Rybchenko case FSE_AZ_EV_CODE_TX_EV: 1480ad1e3ed8SAndrew Rybchenko should_abort = eep->ee_tx(eep, 1481ad1e3ed8SAndrew Rybchenko &(ev[index]), eecp, arg); 1482ad1e3ed8SAndrew Rybchenko break; 1483ad1e3ed8SAndrew Rybchenko case FSE_AZ_EV_CODE_DRIVER_EV: 1484ad1e3ed8SAndrew Rybchenko should_abort = eep->ee_driver(eep, 1485ad1e3ed8SAndrew Rybchenko &(ev[index]), eecp, arg); 1486ad1e3ed8SAndrew Rybchenko break; 1487ad1e3ed8SAndrew Rybchenko case FSE_AZ_EV_CODE_DRV_GEN_EV: 1488ad1e3ed8SAndrew Rybchenko should_abort = eep->ee_drv_gen(eep, 1489ad1e3ed8SAndrew Rybchenko &(ev[index]), eecp, arg); 1490ad1e3ed8SAndrew Rybchenko break; 1491ad1e3ed8SAndrew Rybchenko #if EFSYS_OPT_MCDI 1492ad1e3ed8SAndrew Rybchenko case FSE_AZ_EV_CODE_MCDI_EVRESPONSE: 1493ad1e3ed8SAndrew Rybchenko should_abort = eep->ee_mcdi(eep, 1494ad1e3ed8SAndrew Rybchenko &(ev[index]), eecp, arg); 1495ad1e3ed8SAndrew Rybchenko break; 1496ad1e3ed8SAndrew Rybchenko #endif 1497ad1e3ed8SAndrew Rybchenko case FSE_AZ_EV_CODE_GLOBAL_EV: 1498ad1e3ed8SAndrew Rybchenko if (eep->ee_global) { 1499ad1e3ed8SAndrew Rybchenko should_abort = eep->ee_global(eep, 1500ad1e3ed8SAndrew Rybchenko &(ev[index]), eecp, arg); 1501ad1e3ed8SAndrew Rybchenko break; 1502ad1e3ed8SAndrew Rybchenko } 1503ad1e3ed8SAndrew Rybchenko /* else fallthrough */ 1504ad1e3ed8SAndrew Rybchenko default: 1505ad1e3ed8SAndrew Rybchenko EFSYS_PROBE3(bad_event, 1506ad1e3ed8SAndrew Rybchenko unsigned int, eep->ee_index, 1507ad1e3ed8SAndrew Rybchenko uint32_t, 1508ad1e3ed8SAndrew Rybchenko EFX_QWORD_FIELD(ev[index], EFX_DWORD_1), 1509ad1e3ed8SAndrew Rybchenko uint32_t, 1510ad1e3ed8SAndrew Rybchenko EFX_QWORD_FIELD(ev[index], EFX_DWORD_0)); 1511ad1e3ed8SAndrew Rybchenko 1512ad1e3ed8SAndrew Rybchenko EFSYS_ASSERT(eecp->eec_exception != NULL); 1513ad1e3ed8SAndrew Rybchenko (void) eecp->eec_exception(arg, 1514ad1e3ed8SAndrew Rybchenko EFX_EXCEPTION_EV_ERROR, code); 1515ad1e3ed8SAndrew Rybchenko should_abort = B_TRUE; 1516ad1e3ed8SAndrew Rybchenko } 1517ad1e3ed8SAndrew Rybchenko if (should_abort) { 1518ad1e3ed8SAndrew Rybchenko /* Ignore subsequent events */ 1519ad1e3ed8SAndrew Rybchenko total = index + 1; 1520ad1e3ed8SAndrew Rybchenko 1521ad1e3ed8SAndrew Rybchenko /* 1522ad1e3ed8SAndrew Rybchenko * Poison batch to ensure the outer 1523ad1e3ed8SAndrew Rybchenko * loop is broken out of. 1524ad1e3ed8SAndrew Rybchenko */ 1525ad1e3ed8SAndrew Rybchenko EFSYS_ASSERT(batch <= EFX_EV_BATCH); 1526ad1e3ed8SAndrew Rybchenko batch += (EFX_EV_BATCH << 1); 1527ad1e3ed8SAndrew Rybchenko EFSYS_ASSERT(total != batch); 1528ad1e3ed8SAndrew Rybchenko break; 1529ad1e3ed8SAndrew Rybchenko } 1530ad1e3ed8SAndrew Rybchenko } 1531ad1e3ed8SAndrew Rybchenko 1532ad1e3ed8SAndrew Rybchenko /* 1533ad1e3ed8SAndrew Rybchenko * Now that the hardware has most likely moved onto dma'ing 1534ad1e3ed8SAndrew Rybchenko * into the next cache line, clear the processed events. Take 1535ad1e3ed8SAndrew Rybchenko * care to only clear out events that we've processed 1536ad1e3ed8SAndrew Rybchenko */ 1537ad1e3ed8SAndrew Rybchenko EFX_SET_QWORD(ev[0]); 1538ad1e3ed8SAndrew Rybchenko offset = (count & eep->ee_mask) * sizeof (efx_qword_t); 1539ad1e3ed8SAndrew Rybchenko for (index = 0; index < total; ++index) { 1540ad1e3ed8SAndrew Rybchenko EFSYS_MEM_WRITEQ(eep->ee_esmp, offset, &(ev[0])); 1541ad1e3ed8SAndrew Rybchenko offset += sizeof (efx_qword_t); 1542ad1e3ed8SAndrew Rybchenko } 1543ad1e3ed8SAndrew Rybchenko 1544ad1e3ed8SAndrew Rybchenko count += total; 1545ad1e3ed8SAndrew Rybchenko 1546ad1e3ed8SAndrew Rybchenko } while (total == batch); 1547ad1e3ed8SAndrew Rybchenko 1548ad1e3ed8SAndrew Rybchenko *countp = count; 1549ad1e3ed8SAndrew Rybchenko } 1550ad1e3ed8SAndrew Rybchenko 1551ad1e3ed8SAndrew Rybchenko #endif /* EFX_OPTS_EF10() || EFSYS_OPT_SIENA */ 1552