aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/sfxge/common/efx_intr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sfxge/common/efx_intr.c')
-rw-r--r--sys/dev/sfxge/common/efx_intr.c436
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 556728df7ba9..d40f57f0b037 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 */