1 /*
   2  * Copyright (c) 2012-2015 Solarflare Communications Inc.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions are met:
   7  *
   8  * 1. Redistributions of source code must retain the above copyright notice,
   9  *    this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright notice,
  11  *    this list of conditions and the following disclaimer in the documentation
  12  *    and/or other materials provided with the distribution.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  *
  26  * The views and conclusions contained in the software and documentation are
  27  * those of the authors and should not be interpreted as representing official
  28  * policies, either expressed or implied, of the FreeBSD Project.
  29  */
  30 
  31 #include "efx.h"
  32 #include "efx_impl.h"
  33 
  34 
  35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
  36 
  37         __checkReturn   efx_rc_t
  38 ef10_intr_init(
  39         __in            efx_nic_t *enp,
  40         __in            efx_intr_type_t type,
  41         __in            efsys_mem_t *esmp)
  42 {
  43         _NOTE(ARGUNUSED(enp, type, esmp))
  44         return (0);
  45 }
  46 
  47 
  48                         void
  49 ef10_intr_enable(
  50         __in            efx_nic_t *enp)
  51 {
  52         _NOTE(ARGUNUSED(enp))
  53 }
  54 
  55 
  56                         void
  57 ef10_intr_disable(
  58         __in            efx_nic_t *enp)
  59 {
  60         _NOTE(ARGUNUSED(enp))
  61 }
  62 
  63 
  64                         void
  65 ef10_intr_disable_unlocked(
  66         __in            efx_nic_t *enp)
  67 {
  68         _NOTE(ARGUNUSED(enp))
  69 }
  70 
  71 
  72 static  __checkReturn   efx_rc_t
  73 efx_mcdi_trigger_interrupt(
  74         __in            efx_nic_t *enp,
  75         __in            unsigned int level)
  76 {
  77         efx_mcdi_req_t req;
  78         uint8_t payload[MAX(MC_CMD_TRIGGER_INTERRUPT_IN_LEN,
  79                             MC_CMD_TRIGGER_INTERRUPT_OUT_LEN)];
  80         efx_rc_t rc;
  81 
  82         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
  83                     enp->en_family == EFX_FAMILY_MEDFORD);
  84 
  85         if (level >= enp->en_nic_cfg.enc_intr_limit) {
  86                 rc = EINVAL;
  87                 goto fail1;
  88         }
  89 
  90         (void) memset(payload, 0, sizeof (payload));
  91         req.emr_cmd = MC_CMD_TRIGGER_INTERRUPT;
  92         req.emr_in_buf = payload;
  93         req.emr_in_length = MC_CMD_TRIGGER_INTERRUPT_IN_LEN;
  94         req.emr_out_buf = payload;
  95         req.emr_out_length = MC_CMD_TRIGGER_INTERRUPT_OUT_LEN;
  96 
  97         MCDI_IN_SET_DWORD(req, TRIGGER_INTERRUPT_IN_INTR_LEVEL, level);
  98 
  99         efx_mcdi_execute(enp, &req);
 100 
 101         if (req.emr_rc != 0) {
 102                 rc = req.emr_rc;
 103                 goto fail2;
 104         }
 105 
 106         return (0);
 107 
 108 fail2:
 109         EFSYS_PROBE(fail2);
 110 
 111 fail1:
 112         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 113 
 114         return (rc);
 115 }
 116 
 117         __checkReturn   efx_rc_t
 118 ef10_intr_trigger(
 119         __in            efx_nic_t *enp,
 120         __in            unsigned int level)
 121 {
 122         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 123         efx_rc_t rc;
 124 
 125         if (encp->enc_bug41750_workaround) {
 126                 /*
 127                  * bug 41750: Test interrupts don't work on Greenport
 128                  * bug 50084: Test interrupts don't work on VFs
 129                  */
 130                 rc = ENOTSUP;
 131                 goto fail1;
 132         }
 133 
 134         if ((rc = efx_mcdi_trigger_interrupt(enp, level)) != 0)
 135                 goto fail2;
 136 
 137         return (0);
 138 
 139 fail2:
 140         EFSYS_PROBE(fail2);
 141 fail1:
 142         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 143 
 144         return (rc);
 145 }
 146 
 147                         void
 148 ef10_intr_status_line(
 149         __in            efx_nic_t *enp,
 150         __out           boolean_t *fatalp,
 151         __out           uint32_t *qmaskp)
 152 {
 153         efx_dword_t dword;
 154 
 155         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
 156                     enp->en_family == EFX_FAMILY_MEDFORD);
 157 
 158         /* Read the queue mask and implicitly acknowledge the interrupt. */
 159         EFX_BAR_READD(enp, ER_DZ_BIU_INT_ISR_REG, &dword, B_FALSE);
 160         *qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
 161 
 162         EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
 163 
 164         *fatalp = B_FALSE;
 165 }
 166 
 167                         void
 168 ef10_intr_status_message(
 169         __in            efx_nic_t *enp,
 170         __in            unsigned int message,
 171         __out           boolean_t *fatalp)
 172 {
 173         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
 174                     enp->en_family == EFX_FAMILY_MEDFORD);
 175 
 176         _NOTE(ARGUNUSED(enp, message))
 177 
 178         /* EF10 fatal errors are reported via events */
 179         *fatalp = B_FALSE;
 180 }
 181 
 182                         void
 183 ef10_intr_fatal(
 184         __in            efx_nic_t *enp)
 185 {
 186         /* EF10 fatal errors are reported via events */
 187         _NOTE(ARGUNUSED(enp))
 188 }
 189 
 190                         void
 191 ef10_intr_fini(
 192         __in            efx_nic_t *enp)
 193 {
 194         _NOTE(ARGUNUSED(enp))
 195 }
 196 
 197 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */