efx_intr.c revision 293769
1227569Sphilip/*- 2283514Sarybchik * Copyright (c) 2007-2015 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4227569Sphilip * 5227569Sphilip * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7227569Sphilip * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29227569Sphilip */ 30227569Sphilip 31228078Sphilip#include <sys/cdefs.h> 32228078Sphilip__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_intr.c 293769 2016-01-12 15:28:59Z arybchik $"); 33228078Sphilip 34227569Sphilip#include "efsys.h" 35227569Sphilip#include "efx.h" 36227569Sphilip#include "efx_types.h" 37227569Sphilip#include "efx_regs.h" 38227569Sphilip#include "efx_impl.h" 39227569Sphilip 40283514Sarybchik 41283514Sarybchik#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA 42283514Sarybchik 43291436Sarybchikstatic __checkReturn efx_rc_t 44283514Sarybchikfalconsiena_intr_init( 45283514Sarybchik __in efx_nic_t *enp, 46283514Sarybchik __in efx_intr_type_t type, 47283514Sarybchik __in efsys_mem_t *esmp); 48283514Sarybchik 49283514Sarybchikstatic void 50283514Sarybchikfalconsiena_intr_enable( 51283514Sarybchik __in efx_nic_t *enp); 52283514Sarybchik 53283514Sarybchikstatic void 54283514Sarybchikfalconsiena_intr_disable( 55283514Sarybchik __in efx_nic_t *enp); 56283514Sarybchik 57283514Sarybchikstatic void 58283514Sarybchikfalconsiena_intr_disable_unlocked( 59283514Sarybchik __in efx_nic_t *enp); 60283514Sarybchik 61291436Sarybchikstatic __checkReturn efx_rc_t 62283514Sarybchikfalconsiena_intr_trigger( 63283514Sarybchik __in efx_nic_t *enp, 64283514Sarybchik __in unsigned int level); 65283514Sarybchik 66283514Sarybchikstatic void 67283514Sarybchikfalconsiena_intr_fini( 68283514Sarybchik __in efx_nic_t *enp); 69283514Sarybchik 70293769Sarybchikstatic void 71293769Sarybchikfalconsiena_intr_status_line( 72293769Sarybchik __in efx_nic_t *enp, 73293769Sarybchik __out boolean_t *fatalp, 74293769Sarybchik __out uint32_t *qmaskp); 75283514Sarybchik 76293769Sarybchikstatic void 77293769Sarybchikfalconsiena_intr_status_message( 78293769Sarybchik __in efx_nic_t *enp, 79293769Sarybchik __in unsigned int message, 80293769Sarybchik __out boolean_t *fatalp); 81283514Sarybchik 82283514Sarybchikstatic void 83283514Sarybchikfalconsiena_intr_fatal( 84283514Sarybchik __in efx_nic_t *enp); 85283514Sarybchik 86293769Sarybchikstatic __checkReturn boolean_t 87293769Sarybchikfalconsiena_intr_check_fatal( 88293769Sarybchik __in efx_nic_t *enp); 89293769Sarybchik 90293769Sarybchik 91283514Sarybchik#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */ 92283514Sarybchik 93283514Sarybchik 94283514Sarybchik#if EFSYS_OPT_FALCON 95283514Sarybchikstatic efx_intr_ops_t __efx_intr_falcon_ops = { 96283514Sarybchik falconsiena_intr_init, /* eio_init */ 97283514Sarybchik falconsiena_intr_enable, /* eio_enable */ 98283514Sarybchik falconsiena_intr_disable, /* eio_disable */ 99283514Sarybchik falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */ 100283514Sarybchik falconsiena_intr_trigger, /* eio_trigger */ 101293769Sarybchik falconsiena_intr_status_line, /* eio_status_line */ 102293769Sarybchik falconsiena_intr_status_message, /* eio_status_message */ 103293769Sarybchik falconsiena_intr_fatal, /* eio_fatal */ 104283514Sarybchik falconsiena_intr_fini, /* eio_fini */ 105283514Sarybchik}; 106283514Sarybchik#endif /* EFSYS_OPT_FALCON */ 107283514Sarybchik 108283514Sarybchik#if EFSYS_OPT_SIENA 109283514Sarybchikstatic efx_intr_ops_t __efx_intr_siena_ops = { 110283514Sarybchik falconsiena_intr_init, /* eio_init */ 111283514Sarybchik falconsiena_intr_enable, /* eio_enable */ 112283514Sarybchik falconsiena_intr_disable, /* eio_disable */ 113283514Sarybchik falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */ 114283514Sarybchik falconsiena_intr_trigger, /* eio_trigger */ 115293769Sarybchik falconsiena_intr_status_line, /* eio_status_line */ 116293769Sarybchik falconsiena_intr_status_message, /* eio_status_message */ 117293769Sarybchik falconsiena_intr_fatal, /* eio_fatal */ 118283514Sarybchik falconsiena_intr_fini, /* eio_fini */ 119283514Sarybchik}; 120283514Sarybchik#endif /* EFSYS_OPT_SIENA */ 121283514Sarybchik 122293751Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 123293751Sarybchikstatic efx_intr_ops_t __efx_intr_ef10_ops = { 124293751Sarybchik ef10_intr_init, /* eio_init */ 125293751Sarybchik ef10_intr_enable, /* eio_enable */ 126293751Sarybchik ef10_intr_disable, /* eio_disable */ 127293751Sarybchik ef10_intr_disable_unlocked, /* eio_disable_unlocked */ 128293751Sarybchik ef10_intr_trigger, /* eio_trigger */ 129293769Sarybchik ef10_intr_status_line, /* eio_status_line */ 130293769Sarybchik ef10_intr_status_message, /* eio_status_message */ 131293769Sarybchik ef10_intr_fatal, /* eio_fatal */ 132293751Sarybchik ef10_intr_fini, /* eio_fini */ 133283514Sarybchik}; 134293751Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 135283514Sarybchik 136291436Sarybchik __checkReturn efx_rc_t 137227569Sphilipefx_intr_init( 138227569Sphilip __in efx_nic_t *enp, 139227569Sphilip __in efx_intr_type_t type, 140227569Sphilip __in efsys_mem_t *esmp) 141227569Sphilip{ 142227569Sphilip efx_intr_t *eip = &(enp->en_intr); 143283514Sarybchik efx_intr_ops_t *eiop; 144291436Sarybchik efx_rc_t rc; 145227569Sphilip 146227569Sphilip EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 147227569Sphilip EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 148227569Sphilip 149227569Sphilip if (enp->en_mod_flags & EFX_MOD_INTR) { 150227569Sphilip rc = EINVAL; 151227569Sphilip goto fail1; 152227569Sphilip } 153227569Sphilip 154283514Sarybchik eip->ei_esmp = esmp; 155283514Sarybchik eip->ei_type = type; 156283514Sarybchik eip->ei_level = 0; 157283514Sarybchik 158227569Sphilip enp->en_mod_flags |= EFX_MOD_INTR; 159227569Sphilip 160283514Sarybchik switch (enp->en_family) { 161283514Sarybchik#if EFSYS_OPT_FALCON 162283514Sarybchik case EFX_FAMILY_FALCON: 163283514Sarybchik eiop = (efx_intr_ops_t *)&__efx_intr_falcon_ops; 164283514Sarybchik break; 165283514Sarybchik#endif /* EFSYS_OPT_FALCON */ 166227569Sphilip 167283514Sarybchik#if EFSYS_OPT_SIENA 168283514Sarybchik case EFX_FAMILY_SIENA: 169283514Sarybchik eiop = (efx_intr_ops_t *)&__efx_intr_siena_ops; 170283514Sarybchik break; 171283514Sarybchik#endif /* EFSYS_OPT_SIENA */ 172283514Sarybchik 173283514Sarybchik#if EFSYS_OPT_HUNTINGTON 174283514Sarybchik case EFX_FAMILY_HUNTINGTON: 175293751Sarybchik eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops; 176283514Sarybchik break; 177283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 178283514Sarybchik 179293751Sarybchik#if EFSYS_OPT_MEDFORD 180293751Sarybchik case EFX_FAMILY_MEDFORD: 181293751Sarybchik eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops; 182293751Sarybchik break; 183293751Sarybchik#endif /* EFSYS_OPT_MEDFORD */ 184293751Sarybchik 185283514Sarybchik default: 186283514Sarybchik EFSYS_ASSERT(B_FALSE); 187283514Sarybchik rc = ENOTSUP; 188283514Sarybchik goto fail2; 189283514Sarybchik } 190283514Sarybchik 191283514Sarybchik if ((rc = eiop->eio_init(enp, type, esmp)) != 0) 192283514Sarybchik goto fail3; 193283514Sarybchik 194283514Sarybchik eip->ei_eiop = eiop; 195283514Sarybchik 196283514Sarybchik return (0); 197283514Sarybchik 198283514Sarybchikfail3: 199283514Sarybchik EFSYS_PROBE(fail3); 200283514Sarybchikfail2: 201283514Sarybchik EFSYS_PROBE(fail2); 202283514Sarybchikfail1: 203291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 204283514Sarybchik 205283514Sarybchik return (rc); 206283514Sarybchik} 207283514Sarybchik 208283514Sarybchik void 209283514Sarybchikefx_intr_fini( 210283514Sarybchik __in efx_nic_t *enp) 211283514Sarybchik{ 212283514Sarybchik efx_intr_t *eip = &(enp->en_intr); 213283514Sarybchik efx_intr_ops_t *eiop = eip->ei_eiop; 214283514Sarybchik 215283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 216283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); 217283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 218283514Sarybchik 219283514Sarybchik eiop->eio_fini(enp); 220283514Sarybchik 221283514Sarybchik enp->en_mod_flags &= ~EFX_MOD_INTR; 222283514Sarybchik} 223283514Sarybchik 224283514Sarybchik void 225283514Sarybchikefx_intr_enable( 226283514Sarybchik __in efx_nic_t *enp) 227283514Sarybchik{ 228283514Sarybchik efx_intr_t *eip = &(enp->en_intr); 229283514Sarybchik efx_intr_ops_t *eiop = eip->ei_eiop; 230283514Sarybchik 231283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 232283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 233283514Sarybchik 234283514Sarybchik eiop->eio_enable(enp); 235283514Sarybchik} 236283514Sarybchik 237283514Sarybchik void 238283514Sarybchikefx_intr_disable( 239283514Sarybchik __in efx_nic_t *enp) 240283514Sarybchik{ 241283514Sarybchik efx_intr_t *eip = &(enp->en_intr); 242283514Sarybchik efx_intr_ops_t *eiop = eip->ei_eiop; 243283514Sarybchik 244283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 245283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 246283514Sarybchik 247283514Sarybchik eiop->eio_disable(enp); 248283514Sarybchik} 249283514Sarybchik 250283514Sarybchik void 251283514Sarybchikefx_intr_disable_unlocked( 252283514Sarybchik __in efx_nic_t *enp) 253283514Sarybchik{ 254283514Sarybchik efx_intr_t *eip = &(enp->en_intr); 255283514Sarybchik efx_intr_ops_t *eiop = eip->ei_eiop; 256283514Sarybchik 257283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 258283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 259283514Sarybchik 260283514Sarybchik eiop->eio_disable_unlocked(enp); 261283514Sarybchik} 262283514Sarybchik 263283514Sarybchik 264291436Sarybchik __checkReturn efx_rc_t 265283514Sarybchikefx_intr_trigger( 266283514Sarybchik __in efx_nic_t *enp, 267283514Sarybchik __in unsigned int level) 268283514Sarybchik{ 269283514Sarybchik efx_intr_t *eip = &(enp->en_intr); 270283514Sarybchik efx_intr_ops_t *eiop = eip->ei_eiop; 271283514Sarybchik 272283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 273283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 274283514Sarybchik 275283514Sarybchik return (eiop->eio_trigger(enp, level)); 276283514Sarybchik} 277283514Sarybchik 278283514Sarybchik void 279283514Sarybchikefx_intr_status_line( 280283514Sarybchik __in efx_nic_t *enp, 281283514Sarybchik __out boolean_t *fatalp, 282283514Sarybchik __out uint32_t *qmaskp) 283283514Sarybchik{ 284283514Sarybchik efx_intr_t *eip = &(enp->en_intr); 285293769Sarybchik efx_intr_ops_t *eiop = eip->ei_eiop; 286283514Sarybchik 287283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 288283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 289283514Sarybchik 290293769Sarybchik eiop->eio_status_line(enp, fatalp, qmaskp); 291283514Sarybchik} 292283514Sarybchik 293283514Sarybchik void 294283514Sarybchikefx_intr_status_message( 295283514Sarybchik __in efx_nic_t *enp, 296283514Sarybchik __in unsigned int message, 297283514Sarybchik __out boolean_t *fatalp) 298283514Sarybchik{ 299283514Sarybchik efx_intr_t *eip = &(enp->en_intr); 300293769Sarybchik efx_intr_ops_t *eiop = eip->ei_eiop; 301283514Sarybchik 302283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 303283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 304283514Sarybchik 305293769Sarybchik eiop->eio_status_message(enp, message, fatalp); 306283514Sarybchik} 307283514Sarybchik 308283514Sarybchik void 309283514Sarybchikefx_intr_fatal( 310283514Sarybchik __in efx_nic_t *enp) 311283514Sarybchik{ 312293769Sarybchik efx_intr_t *eip = &(enp->en_intr); 313293769Sarybchik efx_intr_ops_t *eiop = eip->ei_eiop; 314293769Sarybchik 315283514Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 316283514Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 317283514Sarybchik 318293769Sarybchik eiop->eio_fatal(enp); 319283514Sarybchik} 320283514Sarybchik 321283514Sarybchik 322283514Sarybchik/* ************************************************************************* */ 323283514Sarybchik/* ************************************************************************* */ 324283514Sarybchik/* ************************************************************************* */ 325283514Sarybchik 326283514Sarybchik#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA 327283514Sarybchik 328291436Sarybchikstatic __checkReturn efx_rc_t 329283514Sarybchikfalconsiena_intr_init( 330283514Sarybchik __in efx_nic_t *enp, 331283514Sarybchik __in efx_intr_type_t type, 332283514Sarybchik __in efsys_mem_t *esmp) 333283514Sarybchik{ 334283514Sarybchik efx_intr_t *eip = &(enp->en_intr); 335283514Sarybchik efx_oword_t oword; 336283514Sarybchik 337283514Sarybchik /* 338227569Sphilip * bug17213 workaround. 339227569Sphilip * 340227569Sphilip * Under legacy interrupts, don't share a level between fatal 341227569Sphilip * interrupts and event queue interrupts. Under MSI-X, they 342227569Sphilip * must share, or we won't get an interrupt. 343227569Sphilip */ 344227569Sphilip if (enp->en_family == EFX_FAMILY_SIENA && 345227569Sphilip eip->ei_type == EFX_INTR_LINE) 346227569Sphilip eip->ei_level = 0x1f; 347227569Sphilip else 348227569Sphilip eip->ei_level = 0; 349227569Sphilip 350227569Sphilip /* Enable all the genuinely fatal interrupts */ 351227569Sphilip EFX_SET_OWORD(oword); 352227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0); 353227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0); 354227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0); 355227569Sphilip if (enp->en_family >= EFX_FAMILY_SIENA) 356227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0); 357227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword); 358227569Sphilip 359227569Sphilip /* Set up the interrupt address register */ 360227569Sphilip EFX_POPULATE_OWORD_3(oword, 361227569Sphilip FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0, 362227569Sphilip FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff, 363227569Sphilip FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32); 364227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword); 365227569Sphilip 366227569Sphilip return (0); 367227569Sphilip} 368227569Sphilip 369283514Sarybchikstatic void 370283514Sarybchikfalconsiena_intr_enable( 371227569Sphilip __in efx_nic_t *enp) 372227569Sphilip{ 373227569Sphilip efx_intr_t *eip = &(enp->en_intr); 374227569Sphilip efx_oword_t oword; 375227569Sphilip 376227569Sphilip EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); 377227569Sphilip 378227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level); 379227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1); 380227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); 381227569Sphilip} 382227569Sphilip 383283514Sarybchikstatic void 384283514Sarybchikfalconsiena_intr_disable( 385227569Sphilip __in efx_nic_t *enp) 386227569Sphilip{ 387227569Sphilip efx_oword_t oword; 388227569Sphilip 389227569Sphilip EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); 390227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0); 391227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); 392227569Sphilip 393227569Sphilip EFSYS_SPIN(10); 394227569Sphilip} 395227569Sphilip 396283514Sarybchikstatic void 397283514Sarybchikfalconsiena_intr_disable_unlocked( 398227569Sphilip __in efx_nic_t *enp) 399227569Sphilip{ 400227569Sphilip efx_oword_t oword; 401227569Sphilip 402227569Sphilip EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST, 403227569Sphilip &oword, B_FALSE); 404227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0); 405227569Sphilip EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST, 406227569Sphilip &oword, B_FALSE); 407227569Sphilip} 408227569Sphilip 409291436Sarybchikstatic __checkReturn efx_rc_t 410283514Sarybchikfalconsiena_intr_trigger( 411227569Sphilip __in efx_nic_t *enp, 412227569Sphilip __in unsigned int level) 413227569Sphilip{ 414227569Sphilip efx_intr_t *eip = &(enp->en_intr); 415227569Sphilip efx_oword_t oword; 416227569Sphilip unsigned int count; 417227569Sphilip uint32_t sel; 418291436Sarybchik efx_rc_t rc; 419227569Sphilip 420227569Sphilip /* bug16757: No event queues can be initialized */ 421227569Sphilip EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); 422227569Sphilip 423227569Sphilip switch (enp->en_family) { 424227569Sphilip case EFX_FAMILY_FALCON: 425283514Sarybchik if (level >= EFX_NINTR_FALCON) { 426227569Sphilip rc = EINVAL; 427227569Sphilip goto fail1; 428227569Sphilip } 429227569Sphilip break; 430227569Sphilip 431227569Sphilip case EFX_FAMILY_SIENA: 432283514Sarybchik if (level >= EFX_NINTR_SIENA) { 433227569Sphilip rc = EINVAL; 434227569Sphilip goto fail1; 435227569Sphilip } 436227569Sphilip break; 437227569Sphilip 438227569Sphilip default: 439227569Sphilip EFSYS_ASSERT(B_FALSE); 440227569Sphilip break; 441227569Sphilip } 442227569Sphilip 443227569Sphilip if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL)) 444227569Sphilip return (ENOTSUP); /* avoid EFSYS_PROBE() */ 445227569Sphilip 446227569Sphilip sel = level; 447227569Sphilip 448227569Sphilip /* Trigger a test interrupt */ 449227569Sphilip EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); 450227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel); 451227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1); 452227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); 453227569Sphilip 454227569Sphilip /* 455227569Sphilip * Wait up to 100ms for the interrupt to be raised before restoring 456227569Sphilip * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will 457227569Sphilip * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL 458227569Sphilip */ 459227569Sphilip count = 0; 460227569Sphilip do { 461227569Sphilip EFSYS_SPIN(100); /* 100us */ 462227569Sphilip 463227569Sphilip EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); 464227569Sphilip } while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000); 465227569Sphilip 466227569Sphilip EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level); 467227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); 468227569Sphilip 469227569Sphilip return (0); 470227569Sphilip 471227569Sphilipfail1: 472291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 473227569Sphilip 474227569Sphilip return (rc); 475227569Sphilip} 476227569Sphilip 477227569Sphilipstatic __checkReturn boolean_t 478283514Sarybchikfalconsiena_intr_check_fatal( 479227569Sphilip __in efx_nic_t *enp) 480227569Sphilip{ 481227569Sphilip efx_intr_t *eip = &(enp->en_intr); 482227569Sphilip efsys_mem_t *esmp = eip->ei_esmp; 483227569Sphilip efx_oword_t oword; 484227569Sphilip 485227569Sphilip /* Read the syndrome */ 486227569Sphilip EFSYS_MEM_READO(esmp, 0, &oword); 487227569Sphilip 488227569Sphilip if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) { 489227569Sphilip EFSYS_PROBE(fatal); 490227569Sphilip 491227569Sphilip /* Clear the fatal interrupt condition */ 492227569Sphilip EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0); 493227569Sphilip EFSYS_MEM_WRITEO(esmp, 0, &oword); 494227569Sphilip 495227569Sphilip return (B_TRUE); 496227569Sphilip } 497227569Sphilip 498227569Sphilip return (B_FALSE); 499227569Sphilip} 500227569Sphilip 501293769Sarybchikstatic void 502293769Sarybchikfalconsiena_intr_status_line( 503293769Sarybchik __in efx_nic_t *enp, 504293769Sarybchik __out boolean_t *fatalp, 505293769Sarybchik __out uint32_t *qmaskp) 506293769Sarybchik{ 507293769Sarybchik efx_intr_t *eip = &(enp->en_intr); 508293769Sarybchik efx_dword_t dword; 509293769Sarybchik 510293769Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 511293769Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 512293769Sarybchik 513293769Sarybchik /* 514293769Sarybchik * Read the queue mask and implicitly acknowledge the 515293769Sarybchik * interrupt. 516293769Sarybchik */ 517293769Sarybchik EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE); 518293769Sarybchik *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 519293769Sarybchik 520293769Sarybchik EFSYS_PROBE1(qmask, uint32_t, *qmaskp); 521293769Sarybchik 522293769Sarybchik if (*qmaskp & (1U << eip->ei_level)) 523293769Sarybchik *fatalp = falconsiena_intr_check_fatal(enp); 524293769Sarybchik else 525293769Sarybchik *fatalp = B_FALSE; 526293769Sarybchik} 527293769Sarybchik 528293769Sarybchikstatic void 529293769Sarybchikfalconsiena_intr_status_message( 530293769Sarybchik __in efx_nic_t *enp, 531293769Sarybchik __in unsigned int message, 532293769Sarybchik __out boolean_t *fatalp) 533293769Sarybchik{ 534293769Sarybchik efx_intr_t *eip = &(enp->en_intr); 535293769Sarybchik 536293769Sarybchik EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 537293769Sarybchik EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); 538293769Sarybchik 539293769Sarybchik if (message == eip->ei_level) 540293769Sarybchik *fatalp = falconsiena_intr_check_fatal(enp); 541293769Sarybchik else 542293769Sarybchik *fatalp = B_FALSE; 543293769Sarybchik} 544293769Sarybchik 545293769Sarybchik 546283514Sarybchikstatic void 547283514Sarybchikfalconsiena_intr_fatal( 548227569Sphilip __in efx_nic_t *enp) 549227569Sphilip{ 550227569Sphilip#if EFSYS_OPT_DECODE_INTR_FATAL 551227569Sphilip efx_oword_t fatal; 552227569Sphilip efx_oword_t mem_per; 553227569Sphilip 554227569Sphilip EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal); 555227569Sphilip EFX_ZERO_OWORD(mem_per); 556227569Sphilip 557227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 || 558227569Sphilip EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0) 559227569Sphilip EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per); 560227569Sphilip 561227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0) 562227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0); 563227569Sphilip 564227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0) 565227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0); 566227569Sphilip 567227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0) 568227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR, 569227569Sphilip EFX_OWORD_FIELD(mem_per, EFX_DWORD_0), 570227569Sphilip EFX_OWORD_FIELD(mem_per, EFX_DWORD_1)); 571227569Sphilip 572227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0) 573227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0); 574227569Sphilip 575227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0) 576227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0); 577227569Sphilip 578227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0) 579227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0); 580227569Sphilip 581227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0) 582227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0); 583227569Sphilip 584227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0) 585227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0); 586227569Sphilip 587227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0) 588227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0); 589227569Sphilip 590227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0) 591227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0); 592227569Sphilip 593227569Sphilip if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0) 594227569Sphilip EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR, 595227569Sphilip EFX_OWORD_FIELD(mem_per, EFX_DWORD_0), 596227569Sphilip EFX_OWORD_FIELD(mem_per, EFX_DWORD_1)); 597227569Sphilip#else 598227569Sphilip EFSYS_ASSERT(0); 599227569Sphilip#endif 600227569Sphilip} 601227569Sphilip 602283514Sarybchikstatic void 603283514Sarybchikfalconsiena_intr_fini( 604227569Sphilip __in efx_nic_t *enp) 605227569Sphilip{ 606227569Sphilip efx_oword_t oword; 607227569Sphilip 608227569Sphilip /* Clear the interrupt address register */ 609227569Sphilip EFX_ZERO_OWORD(oword); 610227569Sphilip EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword); 611283514Sarybchik} 612227569Sphilip 613283514Sarybchik#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */ 614