diff options
Diffstat (limited to 'sys/dev/sfxge/common/efx_intr.c')
-rw-r--r-- | sys/dev/sfxge/common/efx_intr.c | 436 |
1 files changed, 329 insertions, 107 deletions
diff --git a/sys/dev/sfxge/common/efx_intr.c b/sys/dev/sfxge/common/efx_intr.c index 556728d..d40f57f 100644 --- a/sys/dev/sfxge/common/efx_intr.c +++ b/sys/dev/sfxge/common/efx_intr.c @@ -1,26 +1,31 @@ /*- - * Copyright 2007-2009 Solarflare Communications Inc. All rights reserved. + * Copyright (c) 2007-2015 Solarflare Communications Inc. + * All rights reserved. * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * modification, are permitted provided that the following conditions are met: * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing official + * policies, either expressed or implied, of the FreeBSD Project. */ #include <sys/cdefs.h> @@ -32,6 +37,82 @@ __FBSDID("$FreeBSD$"); #include "efx_regs.h" #include "efx_impl.h" + +#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA + +static __checkReturn int +falconsiena_intr_init( + __in efx_nic_t *enp, + __in efx_intr_type_t type, + __in efsys_mem_t *esmp); + +static void +falconsiena_intr_enable( + __in efx_nic_t *enp); + +static void +falconsiena_intr_disable( + __in efx_nic_t *enp); + +static void +falconsiena_intr_disable_unlocked( + __in efx_nic_t *enp); + +static __checkReturn int +falconsiena_intr_trigger( + __in efx_nic_t *enp, + __in unsigned int level); + +static void +falconsiena_intr_fini( + __in efx_nic_t *enp); + + +static __checkReturn boolean_t +falconsiena_intr_check_fatal( + __in efx_nic_t *enp); + +static void +falconsiena_intr_fatal( + __in efx_nic_t *enp); + +#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */ + + +#if EFSYS_OPT_FALCON +static efx_intr_ops_t __efx_intr_falcon_ops = { + falconsiena_intr_init, /* eio_init */ + falconsiena_intr_enable, /* eio_enable */ + falconsiena_intr_disable, /* eio_disable */ + falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */ + falconsiena_intr_trigger, /* eio_trigger */ + falconsiena_intr_fini, /* eio_fini */ +}; +#endif /* EFSYS_OPT_FALCON */ + +#if EFSYS_OPT_SIENA +static efx_intr_ops_t __efx_intr_siena_ops = { + falconsiena_intr_init, /* eio_init */ + falconsiena_intr_enable, /* eio_enable */ + falconsiena_intr_disable, /* eio_disable */ + falconsiena_intr_disable_unlocked, /* eio_disable_unlocked */ + falconsiena_intr_trigger, /* eio_trigger */ + falconsiena_intr_fini, /* eio_fini */ +}; +#endif /* EFSYS_OPT_SIENA */ + +#if EFSYS_OPT_HUNTINGTON +static efx_intr_ops_t __efx_intr_hunt_ops = { + hunt_intr_init, /* eio_init */ + hunt_intr_enable, /* eio_enable */ + hunt_intr_disable, /* eio_disable */ + hunt_intr_disable_unlocked, /* eio_disable_unlocked */ + hunt_intr_trigger, /* eio_trigger */ + hunt_intr_fini, /* eio_fini */ +}; +#endif /* EFSYS_OPT_HUNTINGTON */ + + __checkReturn int efx_intr_init( __in efx_nic_t *enp, @@ -39,7 +120,7 @@ efx_intr_init( __in efsys_mem_t *esmp) { efx_intr_t *eip = &(enp->en_intr); - efx_oword_t oword; + efx_intr_ops_t *eiop; int rc; EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); @@ -50,10 +131,219 @@ efx_intr_init( goto fail1; } + eip->ei_esmp = esmp; + eip->ei_type = type; + eip->ei_level = 0; + enp->en_mod_flags |= EFX_MOD_INTR; - eip->ei_type = type; - eip->ei_esmp = esmp; + switch (enp->en_family) { +#if EFSYS_OPT_FALCON + case EFX_FAMILY_FALCON: + eiop = (efx_intr_ops_t *)&__efx_intr_falcon_ops; + break; +#endif /* EFSYS_OPT_FALCON */ + +#if EFSYS_OPT_SIENA + case EFX_FAMILY_SIENA: + eiop = (efx_intr_ops_t *)&__efx_intr_siena_ops; + break; +#endif /* EFSYS_OPT_SIENA */ + +#if EFSYS_OPT_HUNTINGTON + case EFX_FAMILY_HUNTINGTON: + eiop = (efx_intr_ops_t *)&__efx_intr_hunt_ops; + break; +#endif /* EFSYS_OPT_HUNTINGTON */ + + default: + EFSYS_ASSERT(B_FALSE); + rc = ENOTSUP; + goto fail2; + } + + if ((rc = eiop->eio_init(enp, type, esmp)) != 0) + goto fail3; + + eip->ei_eiop = eiop; + + return (0); + +fail3: + EFSYS_PROBE(fail3); +fail2: + EFSYS_PROBE(fail2); +fail1: + EFSYS_PROBE1(fail1, int, rc); + + return (rc); +} + + void +efx_intr_fini( + __in efx_nic_t *enp) +{ + efx_intr_t *eip = &(enp->en_intr); + efx_intr_ops_t *eiop = eip->ei_eiop; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); + + eiop->eio_fini(enp); + + enp->en_mod_flags &= ~EFX_MOD_INTR; +} + + void +efx_intr_enable( + __in efx_nic_t *enp) +{ + efx_intr_t *eip = &(enp->en_intr); + efx_intr_ops_t *eiop = eip->ei_eiop; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); + + eiop->eio_enable(enp); +} + + void +efx_intr_disable( + __in efx_nic_t *enp) +{ + efx_intr_t *eip = &(enp->en_intr); + efx_intr_ops_t *eiop = eip->ei_eiop; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); + + eiop->eio_disable(enp); +} + + void +efx_intr_disable_unlocked( + __in efx_nic_t *enp) +{ + efx_intr_t *eip = &(enp->en_intr); + efx_intr_ops_t *eiop = eip->ei_eiop; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); + + eiop->eio_disable_unlocked(enp); +} + + + __checkReturn int +efx_intr_trigger( + __in efx_nic_t *enp, + __in unsigned int level) +{ + efx_intr_t *eip = &(enp->en_intr); + efx_intr_ops_t *eiop = eip->ei_eiop; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); + + return (eiop->eio_trigger(enp, level)); +} + + void +efx_intr_status_line( + __in efx_nic_t *enp, + __out boolean_t *fatalp, + __out uint32_t *qmaskp) +{ + efx_intr_t *eip = &(enp->en_intr); + efx_dword_t dword; + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); + + /* Ensure Huntington and Falcon/Siena ISR at same location */ + EFX_STATIC_ASSERT(FR_BZ_INT_ISR0_REG_OFST == + ER_DZ_BIU_INT_ISR_REG_OFST); + + /* + * Read the queue mask and implicitly acknowledge the + * interrupt. + */ + EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE); + *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0); + + EFSYS_PROBE1(qmask, uint32_t, *qmaskp); + +#if EFSYS_OPT_HUNTINGTON + if (enp->en_family == EFX_FAMILY_HUNTINGTON) { + /* Huntington reports fatal errors via events */ + *fatalp = B_FALSE; + return; + } +#endif + if (*qmaskp & (1U << eip->ei_level)) + *fatalp = falconsiena_intr_check_fatal(enp); + else + *fatalp = B_FALSE; +} + + void +efx_intr_status_message( + __in efx_nic_t *enp, + __in unsigned int message, + __out boolean_t *fatalp) +{ + efx_intr_t *eip = &(enp->en_intr); + + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); + +#if EFSYS_OPT_HUNTINGTON + if (enp->en_family == EFX_FAMILY_HUNTINGTON) { + /* Huntington reports fatal errors via events */ + *fatalp = B_FALSE; + return; + } +#endif + if (message == eip->ei_level) + *fatalp = falconsiena_intr_check_fatal(enp); + else + *fatalp = B_FALSE; +} + + void +efx_intr_fatal( + __in efx_nic_t *enp) +{ + EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); + EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); + +#if EFSYS_OPT_HUNTINGTON + if (enp->en_family == EFX_FAMILY_HUNTINGTON) { + /* Huntington reports fatal errors via events */ + return; + } +#endif +#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA + falconsiena_intr_fatal(enp); +#endif +} + + +/* ************************************************************************* */ +/* ************************************************************************* */ +/* ************************************************************************* */ + +#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA + +static __checkReturn int +falconsiena_intr_init( + __in efx_nic_t *enp, + __in efx_intr_type_t type, + __in efsys_mem_t *esmp) +{ + efx_intr_t *eip = &(enp->en_intr); + efx_oword_t oword; /* * bug17213 workaround. @@ -85,23 +375,15 @@ efx_intr_init( EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword); return (0); - -fail1: - EFSYS_PROBE1(fail1, int, rc); - - return (rc); } - void -efx_intr_enable( +static void +falconsiena_intr_enable( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); efx_oword_t oword; - EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); - EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level); @@ -109,15 +391,12 @@ efx_intr_enable( EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); } - void -efx_intr_disable( +static void +falconsiena_intr_disable( __in efx_nic_t *enp) { efx_oword_t oword; - EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); - EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword); EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0); EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword); @@ -125,15 +404,12 @@ efx_intr_disable( EFSYS_SPIN(10); } - void -efx_intr_disable_unlocked( +static void +falconsiena_intr_disable_unlocked( __in efx_nic_t *enp) { efx_oword_t oword; - EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); - EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST, &oword, B_FALSE); EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0); @@ -141,8 +417,8 @@ efx_intr_disable_unlocked( &oword, B_FALSE); } - __checkReturn int -efx_intr_trigger( +static __checkReturn int +falconsiena_intr_trigger( __in efx_nic_t *enp, __in unsigned int level) { @@ -152,22 +428,19 @@ efx_intr_trigger( uint32_t sel; int rc; - EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); - /* bug16757: No event queues can be initialized */ EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV)); switch (enp->en_family) { case EFX_FAMILY_FALCON: - if (level > EFX_NINTR_FALCON) { + if (level >= EFX_NINTR_FALCON) { rc = EINVAL; goto fail1; } break; case EFX_FAMILY_SIENA: - if (level > EFX_NINTR_SIENA) { + if (level >= EFX_NINTR_SIENA) { rc = EINVAL; goto fail1; } @@ -213,7 +486,7 @@ fail1: } static __checkReturn boolean_t -efx_intr_check_fatal( +falconsiena_intr_check_fatal( __in efx_nic_t *enp) { efx_intr_t *eip = &(enp->en_intr); @@ -236,61 +509,14 @@ efx_intr_check_fatal( return (B_FALSE); } - void -efx_intr_status_line( - __in efx_nic_t *enp, - __out boolean_t *fatalp, - __out uint32_t *qmaskp) -{ - efx_intr_t *eip = &(enp->en_intr); - efx_dword_t dword; - - EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); - - /* - * Read the queue mask and implicitly acknowledge the - * interrupt. - */ - EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE); - *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0); - - EFSYS_PROBE1(qmask, uint32_t, *qmaskp); - - if (*qmaskp & (1U << eip->ei_level)) - *fatalp = efx_intr_check_fatal(enp); - else - *fatalp = B_FALSE; -} - - void -efx_intr_status_message( - __in efx_nic_t *enp, - __in unsigned int message, - __out boolean_t *fatalp) -{ - efx_intr_t *eip = &(enp->en_intr); - - EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); - - if (message == eip->ei_level) - *fatalp = efx_intr_check_fatal(enp); - else - *fatalp = B_FALSE; -} - - void -efx_intr_fatal( +static void +falconsiena_intr_fatal( __in efx_nic_t *enp) { #if EFSYS_OPT_DECODE_INTR_FATAL efx_oword_t fatal; efx_oword_t mem_per; - EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); - EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal); EFX_ZERO_OWORD(mem_per); @@ -339,19 +565,15 @@ efx_intr_fatal( #endif } - void -efx_intr_fini( +static void +falconsiena_intr_fini( __in efx_nic_t *enp) { efx_oword_t oword; - EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC); - EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR); - /* Clear the interrupt address register */ EFX_ZERO_OWORD(oword); EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword); - - enp->en_mod_flags &= ~EFX_MOD_INTR; } + +#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */ |