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 #if EFSYS_OPT_MCDI
  38 
  39 #ifndef WITH_MCDI_V2
  40 #error "WITH_MCDI_V2 required for EF10 MCDIv2 commands."
  41 #endif
  42 
  43 
  44         __checkReturn   efx_rc_t
  45 ef10_mcdi_init(
  46         __in            efx_nic_t *enp,
  47         __in            const efx_mcdi_transport_t *emtp)
  48 {
  49         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
  50         efsys_mem_t *esmp = emtp->emt_dma_mem;
  51         efx_dword_t dword;
  52         efx_rc_t rc;
  53 
  54         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
  55                     enp->en_family == EFX_FAMILY_MEDFORD);
  56         EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
  57 
  58         /*
  59          * All EF10 firmware supports MCDIv2 and MCDIv1.
  60          * Medford BootROM supports MCDIv2 and MCDIv1.
  61          * Huntington BootROM supports MCDIv1 only.
  62          */
  63         emip->emi_max_version = 2;
  64 
  65         /* A host DMA buffer is required for EF10 MCDI */
  66         if (esmp == NULL) {
  67                 rc = EINVAL;
  68                 goto fail1;
  69         }
  70 
  71         /*
  72          * Ensure that the MC doorbell is in a known state before issuing MCDI
  73          * commands. The recovery algorithm requires that the MC command buffer
  74          * must be 256 byte aligned. See bug24769.
  75          */
  76         if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
  77                 rc = EINVAL;
  78                 goto fail2;
  79         }
  80         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
  81         EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
  82 
  83         /* Save initial MC reboot status */
  84         (void) ef10_mcdi_poll_reboot(enp);
  85 
  86         /* Start a new epoch (allow fresh MCDI requests to succeed) */
  87         efx_mcdi_new_epoch(enp);
  88 
  89         return (0);
  90 
  91 fail2:
  92         EFSYS_PROBE(fail2);
  93 fail1:
  94         EFSYS_PROBE1(fail1, efx_rc_t, rc);
  95 
  96         return (rc);
  97 }
  98 
  99                         void
 100 ef10_mcdi_fini(
 101         __in            efx_nic_t *enp)
 102 {
 103         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
 104 
 105         emip->emi_new_epoch = B_FALSE;
 106 }
 107 
 108                         void
 109 ef10_mcdi_send_request(
 110         __in            efx_nic_t *enp,
 111         __in            void *hdrp,
 112         __in            size_t hdr_len,
 113         __in            void *sdup,
 114         __in            size_t sdu_len)
 115 {
 116         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
 117         efsys_mem_t *esmp = emtp->emt_dma_mem;
 118         efx_dword_t dword;
 119         unsigned int pos;
 120 
 121         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
 122                     enp->en_family == EFX_FAMILY_MEDFORD);
 123 
 124         /* Write the header */
 125         for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) {
 126                 dword = *(efx_dword_t *)((uint8_t *)hdrp + pos);
 127                 EFSYS_MEM_WRITED(esmp, pos, &dword);
 128         }
 129 
 130         /* Write the payload */
 131         for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
 132                 dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
 133                 EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword);
 134         }
 135 
 136         /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
 137         EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len);
 138         EFSYS_PIO_WRITE_BARRIER();
 139 
 140         /* Ring the doorbell to post the command DMA address to the MC */
 141         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
 142             EFSYS_MEM_ADDR(esmp) >> 32);
 143         EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
 144 
 145         EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
 146             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
 147         EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
 148 }
 149 
 150         __checkReturn   boolean_t
 151 ef10_mcdi_poll_response(
 152         __in            efx_nic_t *enp)
 153 {
 154         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
 155         efsys_mem_t *esmp = emtp->emt_dma_mem;
 156         efx_dword_t hdr;
 157 
 158         EFSYS_MEM_READD(esmp, 0, &hdr);
 159         return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
 160 }
 161 
 162                         void
 163 ef10_mcdi_read_response(
 164         __in                    efx_nic_t *enp,
 165         __out_bcount(length)    void *bufferp,
 166         __in                    size_t offset,
 167         __in                    size_t length)
 168 {
 169         const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
 170         efsys_mem_t *esmp = emtp->emt_dma_mem;
 171         unsigned int pos;
 172         efx_dword_t data;
 173 
 174         for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) {
 175                 EFSYS_MEM_READD(esmp, offset + pos, &data);
 176                 (void) memcpy((uint8_t *)bufferp + pos, &data,
 177                     MIN(sizeof (data), length - pos));
 178         }
 179 }
 180 
 181                         efx_rc_t
 182 ef10_mcdi_poll_reboot(
 183         __in            efx_nic_t *enp)
 184 {
 185         efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
 186         efx_dword_t dword;
 187         uint32_t old_status;
 188         uint32_t new_status;
 189         efx_rc_t rc;
 190 
 191         old_status = emip->emi_mc_reboot_status;
 192 
 193         /* Update MC reboot status word */
 194         EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE);
 195         new_status = dword.ed_u32[0];
 196 
 197         /* MC has rebooted if the value has changed */
 198         if (new_status != old_status) {
 199                 emip->emi_mc_reboot_status = new_status;
 200 
 201                 /*
 202                  * FIXME: Ignore detected MC REBOOT for now.
 203                  *
 204                  * The Siena support for checking for MC reboot from status
 205                  * flags is broken - see comments in siena_mcdi_poll_reboot().
 206                  * As the generic MCDI code is shared the EF10 reboot
 207                  * detection suffers similar problems.
 208                  *
 209                  * Do not report an error when the boot status changes until
 210                  * this can be handled by common code drivers (and reworked to
 211                  * support Siena too).
 212                  */
 213                 _NOTE(CONSTANTCONDITION)
 214                 if (B_FALSE) {
 215                         rc = EIO;
 216                         goto fail1;
 217                 }
 218         }
 219 
 220         return (0);
 221 
 222 fail1:
 223         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 224 
 225         return (rc);
 226 }
 227 
 228         __checkReturn   efx_rc_t
 229 ef10_mcdi_feature_supported(
 230         __in            efx_nic_t *enp,
 231         __in            efx_mcdi_feature_id_t id,
 232         __out           boolean_t *supportedp)
 233 {
 234         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 235         uint32_t privilege_mask = encp->enc_privilege_mask;
 236         efx_rc_t rc;
 237 
 238         EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
 239                     enp->en_family == EFX_FAMILY_MEDFORD);
 240 
 241         /*
 242          * Use privilege mask state at MCDI attach.
 243          */
 244 
 245         switch (id) {
 246         case EFX_MCDI_FEATURE_FW_UPDATE:
 247                 /*
 248                  * Admin privilege must be used prior to introduction of
 249                  * specific flag.
 250                  */
 251                 *supportedp =
 252                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
 253                 break;
 254         case EFX_MCDI_FEATURE_LINK_CONTROL:
 255                 /*
 256                  * Admin privilege used prior to introduction of
 257                  * specific flag.
 258                  */
 259                 *supportedp =
 260                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) ||
 261                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
 262                 break;
 263         case EFX_MCDI_FEATURE_MACADDR_CHANGE:
 264                 /*
 265                  * Admin privilege must be used prior to introduction of
 266                  * mac spoofing privilege (at v4.6), which is used up to
 267                  * introduction of change mac spoofing privilege (at v4.7)
 268                  */
 269                 *supportedp =
 270                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) ||
 271                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
 272                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
 273                 break;
 274         case EFX_MCDI_FEATURE_MAC_SPOOFING:
 275                 /*
 276                  * Admin privilege must be used prior to introduction of
 277                  * mac spoofing privilege (at v4.6), which is used up to
 278                  * introduction of mac spoofing TX privilege (at v4.7)
 279                  */
 280                 *supportedp =
 281                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) ||
 282                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
 283                     EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
 284                 break;
 285         default:
 286                 rc = ENOTSUP;
 287                 goto fail1;
 288         }
 289 
 290         return (0);
 291 
 292 fail1:
 293         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 294 
 295         return (rc);
 296 }
 297 
 298 #endif  /* EFSYS_OPT_MCDI */
 299 
 300 #endif  /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */