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 */