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