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 /* 112 * In older firmware all commands are processed in a single thread, so a long 113 * running command for one PCIe function can block processing for another 114 * function (see bug 61269). 115 * 116 * In newer firmware that supports multithreaded MCDI processing, we can extend 117 * the timeout for long-running requests which we know firmware may choose to 118 * process in a background thread. 119 */ 120 #define EF10_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000) 121 #define EF10_MCDI_CMD_LONG_TIMEOUT_US (60 * 1000 * 1000) 122 123 void 124 ef10_mcdi_get_timeout( 125 __in efx_nic_t *enp, 126 __in efx_mcdi_req_t *emrp, 127 __out uint32_t *timeoutp) 128 { 129 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 130 131 switch (emrp->emr_cmd) { 132 case MC_CMD_POLL_BIST: 133 case MC_CMD_NVRAM_ERASE: 134 case MC_CMD_LICENSING_V3: 135 case MC_CMD_NVRAM_UPDATE_FINISH: 136 if (encp->enc_fw_verified_nvram_update_required != B_FALSE) { 137 /* 138 * Potentially longer running commands, which firmware 139 * may choose to process in a background thread. 140 */ 141 *timeoutp = EF10_MCDI_CMD_LONG_TIMEOUT_US; 142 break; 143 } 144 /* FALLTHRU */ 145 default: 146 *timeoutp = EF10_MCDI_CMD_TIMEOUT_US; 147 break; 148 } 149 } 150 151 void 152 ef10_mcdi_send_request( 153 __in efx_nic_t *enp, 154 __in_bcount(hdr_len) void *hdrp, 155 __in size_t hdr_len, 156 __in_bcount(sdu_len) void *sdup, 157 __in size_t sdu_len) 158 { 159 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 160 efsys_mem_t *esmp = emtp->emt_dma_mem; 161 efx_dword_t dword; 162 unsigned int pos; 163 164 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 165 enp->en_family == EFX_FAMILY_MEDFORD); 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; 217 efx_dword_t data; 218 219 for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) { 220 EFSYS_MEM_READD(esmp, offset + pos, &data); 221 memcpy((uint8_t *)bufferp + pos, &data, 222 MIN(sizeof (data), length - pos)); 223 } 224 } 225 226 efx_rc_t 227 ef10_mcdi_poll_reboot( 228 __in efx_nic_t *enp) 229 { 230 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 231 efx_dword_t dword; 232 uint32_t old_status; 233 uint32_t new_status; 234 efx_rc_t rc; 235 236 old_status = emip->emi_mc_reboot_status; 237 238 /* Update MC reboot status word */ 239 EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE); 240 new_status = dword.ed_u32[0]; 241 242 /* MC has rebooted if the value has changed */ 243 if (new_status != old_status) { 244 emip->emi_mc_reboot_status = new_status; 245 246 /* 247 * FIXME: Ignore detected MC REBOOT for now. 248 * 249 * The Siena support for checking for MC reboot from status 250 * flags is broken - see comments in siena_mcdi_poll_reboot(). 251 * As the generic MCDI code is shared the EF10 reboot 252 * detection suffers similar problems. 253 * 254 * Do not report an error when the boot status changes until 255 * this can be handled by common code drivers (and reworked to 256 * support Siena too). 257 */ 258 _NOTE(CONSTANTCONDITION) 259 if (B_FALSE) { 260 rc = EIO; 261 goto fail1; 262 } 263 } 264 265 return (0); 266 267 fail1: 268 EFSYS_PROBE1(fail1, efx_rc_t, rc); 269 270 return (rc); 271 } 272 273 __checkReturn efx_rc_t 274 ef10_mcdi_feature_supported( 275 __in efx_nic_t *enp, 276 __in efx_mcdi_feature_id_t id, 277 __out boolean_t *supportedp) 278 { 279 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 280 uint32_t privilege_mask = encp->enc_privilege_mask; 281 efx_rc_t rc; 282 283 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 284 enp->en_family == EFX_FAMILY_MEDFORD); 285 286 /* 287 * Use privilege mask state at MCDI attach. 288 */ 289 290 switch (id) { 291 case EFX_MCDI_FEATURE_FW_UPDATE: 292 /* 293 * Admin privilege must be used prior to introduction of 294 * specific flag. 295 */ 296 *supportedp = 297 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 298 break; 299 case EFX_MCDI_FEATURE_LINK_CONTROL: 300 /* 301 * Admin privilege used prior to introduction of 302 * specific flag. 303 */ 304 *supportedp = 305 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) || 306 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 307 break; 308 case EFX_MCDI_FEATURE_MACADDR_CHANGE: 309 /* 310 * Admin privilege must be used prior to introduction of 311 * mac spoofing privilege (at v4.6), which is used up to 312 * introduction of change mac spoofing privilege (at v4.7) 313 */ 314 *supportedp = 315 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) || 316 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || 317 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 318 break; 319 case EFX_MCDI_FEATURE_MAC_SPOOFING: 320 /* 321 * Admin privilege must be used prior to introduction of 322 * mac spoofing privilege (at v4.6), which is used up to 323 * introduction of mac spoofing TX privilege (at v4.7) 324 */ 325 *supportedp = 326 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) || 327 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) || 328 EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN); 329 break; 330 default: 331 rc = ENOTSUP; 332 goto fail1; 333 } 334 335 return (0); 336 337 fail1: 338 EFSYS_PROBE1(fail1, efx_rc_t, rc); 339 340 return (rc); 341 } 342 343 #endif /* EFSYS_OPT_MCDI */ 344 345 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 346