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