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 #include "efx.h" 33 #include "efx_impl.h" 34 35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 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 __checkReturn efx_rc_t 44 ef10_mcdi_init( 45 __in efx_nic_t *enp, 46 __in const efx_mcdi_transport_t *emtp) 47 { 48 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 49 efsys_mem_t *esmp = emtp->emt_dma_mem; 50 efx_dword_t dword; 51 efx_rc_t rc; 52 53 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 54 enp->en_family == EFX_FAMILY_MEDFORD || 55 enp->en_family == EFX_FAMILY_MEDFORD2); 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 /* 109 * In older firmware all commands are processed in a single thread, so a long 110 * running command for one PCIe function can block processing for another 111 * function (see bug 61269). 112 * 113 * In newer firmware that supports multithreaded MCDI processing, we can extend 114 * the timeout for long-running requests which we know firmware may choose to 115 * process in a background thread. 116 */ 117 #define EF10_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000) 118 #define EF10_MCDI_CMD_LONG_TIMEOUT_US (60 * 1000 * 1000) 119 120 void 121 ef10_mcdi_get_timeout( 122 __in efx_nic_t *enp, 123 __in efx_mcdi_req_t *emrp, 124 __out uint32_t *timeoutp) 125 { 126 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 127 128 switch (emrp->emr_cmd) { 129 case MC_CMD_POLL_BIST: 130 case MC_CMD_NVRAM_ERASE: 131 case MC_CMD_LICENSING_V3: 132 case MC_CMD_NVRAM_UPDATE_FINISH: 133 if (encp->enc_nvram_update_verify_result_supported != B_FALSE) { 134 /* 135 * Potentially longer running commands, which firmware 136 * may choose to process in a background thread. 137 */ 138 *timeoutp = EF10_MCDI_CMD_LONG_TIMEOUT_US; 139 break; 140 } 141 /* FALLTHRU */ 142 default: 143 *timeoutp = EF10_MCDI_CMD_TIMEOUT_US; 144 break; 145 } 146 } 147 148 void 149 ef10_mcdi_send_request( 150 __in efx_nic_t *enp, 151 __in_bcount(hdr_len) void *hdrp, 152 __in size_t hdr_len, 153 __in_bcount(sdu_len) void *sdup, 154 __in size_t sdu_len) 155 { 156 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 157 efsys_mem_t *esmp = emtp->emt_dma_mem; 158 efx_dword_t dword; 159 unsigned int pos; 160 161 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 162 enp->en_family == EFX_FAMILY_MEDFORD || 163 enp->en_family == EFX_FAMILY_MEDFORD2); 164 165 /* Write the header */ 166 for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) { 167 dword = *(efx_dword_t *)((uint8_t *)hdrp + pos); 168 EFSYS_MEM_WRITED(esmp, pos, &dword); 169 } 170 171 /* Write the payload */ 172 for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) { 173 dword = *(efx_dword_t *)((uint8_t *)sdup + pos); 174 EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword); 175 } 176 177 /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */ 178 EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len); 179 EFSYS_PIO_WRITE_BARRIER(); 180 181 /* Ring the doorbell to post the command DMA address to the MC */ 182 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 183 EFSYS_MEM_ADDR(esmp) >> 32); 184 EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE); 185 186 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 187 EFSYS_MEM_ADDR(esmp) & 0xffffffff); 188 EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE); 189 } 190 191 __checkReturn boolean_t 192 ef10_mcdi_poll_response( 193 __in efx_nic_t *enp) 194 { 195 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 196 efsys_mem_t *esmp = emtp->emt_dma_mem; 197 efx_dword_t hdr; 198 199 EFSYS_MEM_READD(esmp, 0, &hdr); 200 EFSYS_MEM_READ_BARRIER(); 201 202 return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE); 203 } 204 205 void 206 ef10_mcdi_read_response( 207 __in efx_nic_t *enp, 208 __out_bcount(length) void *bufferp, 209 __in size_t offset, 210 __in size_t length) 211 { 212 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 213 efsys_mem_t *esmp = emtp->emt_dma_mem; 214 unsigned int pos = 0; 215 efx_dword_t data; 216 size_t remaining = length; 217 218 while (remaining > 0) { 219 size_t chunk = MIN(remaining, sizeof (data)); 220 221 EFSYS_MEM_READD(esmp, offset + pos, &data); 222 memcpy((uint8_t *)bufferp + pos, &data, chunk); 223 pos += chunk; 224 remaining -= chunk; 225 } 226 } 227 228 efx_rc_t 229 ef10_mcdi_poll_reboot( 230 __in efx_nic_t *enp) 231 { 232 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 233 efx_dword_t dword; 234 uint32_t old_status; 235 uint32_t new_status; 236 efx_rc_t rc; 237 238 old_status = emip->emi_mc_reboot_status; 239 240 /* Update MC reboot status word */ 241 EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE); 242 new_status = dword.ed_u32[0]; 243 244 /* MC has rebooted if the value has changed */ 245 if (new_status != old_status) { 246 emip->emi_mc_reboot_status = new_status; 247 248 /* 249 * FIXME: Ignore detected MC REBOOT for now. 250 * 251 * The Siena support for checking for MC reboot from status 252 * flags is broken - see comments in siena_mcdi_poll_reboot(). 253 * As the generic MCDI code is shared the EF10 reboot 254 * detection suffers similar problems. 255 * 256 * Do not report an error when the boot status changes until 257 * this can be handled by common code drivers (and reworked to 258 * support Siena too). 259 */ 260 _NOTE(CONSTANTCONDITION) 261 if (B_FALSE) { 262 rc = EIO; 263 goto fail1; 264 } 265 } 266 267 return (0); 268 269 fail1: 270 EFSYS_PROBE1(fail1, efx_rc_t, rc); 271 272 return (rc); 273 } 274 275 __checkReturn efx_rc_t 276 ef10_mcdi_feature_supported( 277 __in efx_nic_t *enp, 278 __in efx_mcdi_feature_id_t id, 279 __out boolean_t *supportedp) 280 { 281 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 282 uint32_t privilege_mask = encp->enc_privilege_mask; 283 efx_rc_t rc; 284 285 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 286 enp->en_family == EFX_FAMILY_MEDFORD || 287 enp->en_family == EFX_FAMILY_MEDFORD2); 288 289 /* 290 * Use privilege mask state at MCDI attach. 291 */ 292 293 switch (id) { 294 case EFX_MCDI_FEATURE_FW_UPDATE: 295 /* 296 * Admin privilege must be used prior to introduction of 297 * specific flag. 298 */ 299 *supportedp = 300 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 301 break; 302 case EFX_MCDI_FEATURE_LINK_CONTROL: 303 /* 304 * Admin privilege used prior to introduction of 305 * specific flag. 306 */ 307 *supportedp = 308 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) || 309 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 310 break; 311 case EFX_MCDI_FEATURE_MACADDR_CHANGE: 312 /* 313 * Admin privilege must be used prior to introduction of 314 * mac spoofing privilege (at v4.6), which is used up to 315 * introduction of change mac spoofing privilege (at v4.7) 316 */ 317 *supportedp = 318 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) || 319 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || 320 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 321 break; 322 case EFX_MCDI_FEATURE_MAC_SPOOFING: 323 /* 324 * Admin privilege must be used prior to introduction of 325 * mac spoofing privilege (at v4.6), which is used up to 326 * introduction of mac spoofing TX privilege (at v4.7) 327 */ 328 *supportedp = 329 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) || 330 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || 331 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 332 break; 333 default: 334 rc = ENOTSUP; 335 goto fail1; 336 } 337 338 return (0); 339 340 fail1: 341 EFSYS_PROBE1(fail1, efx_rc_t, rc); 342 343 return (rc); 344 } 345 346 #endif /* EFSYS_OPT_MCDI */ 347 348 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 349