1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2021 Xilinx, Inc. 4 * Copyright(c) 2012-2019 Solarflare Communications Inc. 5 */ 6 7 #include "efx.h" 8 #include "efx_impl.h" 9 10 #if EFSYS_OPT_SIENA && EFSYS_OPT_MCDI 11 12 #define SIENA_MCDI_PDU(_emip) \ 13 (((emip)->emi_port == 1) \ 14 ? MC_SMEM_P0_PDU_OFST >> 2 \ 15 : MC_SMEM_P1_PDU_OFST >> 2) 16 17 #define SIENA_MCDI_DOORBELL(_emip) \ 18 (((emip)->emi_port == 1) \ 19 ? MC_SMEM_P0_DOORBELL_OFST >> 2 \ 20 : MC_SMEM_P1_DOORBELL_OFST >> 2) 21 22 #define SIENA_MCDI_STATUS(_emip) \ 23 (((emip)->emi_port == 1) \ 24 ? MC_SMEM_P0_STATUS_OFST >> 2 \ 25 : MC_SMEM_P1_STATUS_OFST >> 2) 26 27 28 void 29 siena_mcdi_send_request( 30 __in efx_nic_t *enp, 31 __in_bcount(hdr_len) void *hdrp, 32 __in size_t hdr_len, 33 __in_bcount(sdu_len) void *sdup, 34 __in size_t sdu_len) 35 { 36 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 37 efx_dword_t dword; 38 unsigned int pdur; 39 unsigned int dbr; 40 unsigned int pos; 41 42 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 43 44 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2); 45 pdur = SIENA_MCDI_PDU(emip); 46 dbr = SIENA_MCDI_DOORBELL(emip); 47 48 /* Write the header */ 49 EFSYS_ASSERT3U(hdr_len, ==, sizeof (efx_dword_t)); 50 dword = *(efx_dword_t *)hdrp; 51 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &dword, B_TRUE); 52 53 /* Write the payload */ 54 for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) { 55 dword = *(efx_dword_t *)((uint8_t *)sdup + pos); 56 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, 57 pdur + 1 + (pos >> 2), &dword, B_FALSE); 58 } 59 60 /* Ring the doorbell */ 61 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11); 62 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE); 63 } 64 65 efx_rc_t 66 siena_mcdi_poll_reboot( 67 __in efx_nic_t *enp) 68 { 69 #if 1 70 /* 71 * XXX Bug 25922, bug 26099: This function is not being used 72 * properly. Until its callers are fixed, it should always 73 * return 0. 74 */ 75 _NOTE(ARGUNUSED(enp)) 76 return (0); 77 #else 78 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 79 unsigned int rebootr; 80 efx_dword_t dword; 81 uint32_t value; 82 83 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 84 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2); 85 rebootr = SIENA_MCDI_STATUS(emip); 86 87 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE); 88 value = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 89 90 if (value == 0) 91 return (0); 92 93 EFX_ZERO_DWORD(dword); 94 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE); 95 96 if (value == MC_STATUS_DWORD_ASSERT) 97 return (EINTR); 98 else 99 return (EIO); 100 #endif 101 } 102 103 extern __checkReturn boolean_t 104 siena_mcdi_poll_response( 105 __in efx_nic_t *enp) 106 { 107 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 108 efx_dword_t hdr; 109 unsigned int pdur; 110 111 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2); 112 pdur = SIENA_MCDI_PDU(emip); 113 114 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_FALSE); 115 return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE); 116 } 117 118 void 119 siena_mcdi_read_response( 120 __in efx_nic_t *enp, 121 __out_bcount(length) void *bufferp, 122 __in size_t offset, 123 __in size_t length) 124 { 125 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 126 unsigned int pdur; 127 unsigned int pos = 0; 128 efx_dword_t data; 129 size_t remaining = length; 130 131 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2); 132 pdur = SIENA_MCDI_PDU(emip); 133 134 while (remaining > 0) { 135 size_t chunk = MIN(remaining, sizeof (data)); 136 137 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, 138 pdur + ((offset + pos) >> 2), &data, B_FALSE); 139 memcpy((uint8_t *)bufferp + pos, &data, chunk); 140 pos += chunk; 141 remaining -= chunk; 142 } 143 } 144 145 __checkReturn efx_rc_t 146 siena_mcdi_init( 147 __in efx_nic_t *enp, 148 __in const efx_mcdi_transport_t *mtp) 149 { 150 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 151 efx_oword_t oword; 152 unsigned int portnum; 153 efx_rc_t rc; 154 155 _NOTE(ARGUNUSED(mtp)) 156 157 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA); 158 159 /* Determine the port number to use for MCDI */ 160 EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword); 161 portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM); 162 163 if (portnum == 0) { 164 /* Presumably booted from ROM; only MCDI port 1 will work */ 165 emip->emi_port = 1; 166 } else if (portnum <= 2) { 167 emip->emi_port = portnum; 168 } else { 169 rc = EINVAL; 170 goto fail1; 171 } 172 173 /* Siena BootROM and firmware only support MCDIv1 */ 174 emip->emi_max_version = 1; 175 176 /* 177 * Wipe the atomic reboot status so subsequent MCDI requests succeed. 178 * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the 179 * assertion handler. 180 */ 181 (void) siena_mcdi_poll_reboot(enp); 182 183 return (0); 184 185 fail1: 186 EFSYS_PROBE1(fail1, efx_rc_t, rc); 187 188 return (rc); 189 } 190 191 void 192 siena_mcdi_fini( 193 __in efx_nic_t *enp) 194 { 195 _NOTE(ARGUNUSED(enp)) 196 } 197 198 __checkReturn efx_rc_t 199 siena_mcdi_feature_supported( 200 __in efx_nic_t *enp, 201 __in efx_mcdi_feature_id_t id, 202 __out boolean_t *supportedp) 203 { 204 efx_rc_t rc; 205 206 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); 207 208 switch (id) { 209 case EFX_MCDI_FEATURE_FW_UPDATE: 210 case EFX_MCDI_FEATURE_LINK_CONTROL: 211 case EFX_MCDI_FEATURE_MACADDR_CHANGE: 212 case EFX_MCDI_FEATURE_MAC_SPOOFING: 213 *supportedp = B_TRUE; 214 break; 215 default: 216 rc = ENOTSUP; 217 goto fail1; 218 } 219 220 return (0); 221 222 fail1: 223 EFSYS_PROBE1(fail1, efx_rc_t, rc); 224 225 return (rc); 226 } 227 228 /* Default timeout for MCDI command processing. */ 229 #define SIENA_MCDI_CMD_TIMEOUT_US (10 * 1000 * 1000) 230 231 void 232 siena_mcdi_get_timeout( 233 __in efx_nic_t *enp, 234 __in efx_mcdi_req_t *emrp, 235 __out uint32_t *timeoutp) 236 { 237 _NOTE(ARGUNUSED(enp, emrp)) 238 239 *timeoutp = SIENA_MCDI_CMD_TIMEOUT_US; 240 } 241 242 243 #endif /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */ 244