2 * Copyright (c) 2012-2015 Solarflare Communications Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
38 #if EFSYS_OPT_SIENA && EFSYS_OPT_MCDI
40 #define SIENA_MCDI_PDU(_emip) \
41 (((emip)->emi_port == 1) \
42 ? MC_SMEM_P0_PDU_OFST >> 2 \
43 : MC_SMEM_P1_PDU_OFST >> 2)
45 #define SIENA_MCDI_DOORBELL(_emip) \
46 (((emip)->emi_port == 1) \
47 ? MC_SMEM_P0_DOORBELL_OFST >> 2 \
48 : MC_SMEM_P1_DOORBELL_OFST >> 2)
50 #define SIENA_MCDI_STATUS(_emip) \
51 (((emip)->emi_port == 1) \
52 ? MC_SMEM_P0_STATUS_OFST >> 2 \
53 : MC_SMEM_P1_STATUS_OFST >> 2)
57 siena_mcdi_request_copyin(
59 __in efx_mcdi_req_t *emrp,
60 __in unsigned int seq,
61 __in boolean_t ev_cpl,
62 __in boolean_t new_epoch)
64 #if EFSYS_OPT_MCDI_LOGGING
65 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
67 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
75 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
76 _NOTE(ARGUNUSED(new_epoch))
78 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
79 pdur = SIENA_MCDI_PDU(emip);
80 dbr = SIENA_MCDI_DOORBELL(emip);
84 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
86 /* Construct the header in shared memory */
87 EFX_POPULATE_DWORD_6(hdr,
88 MCDI_HEADER_CODE, emrp->emr_cmd,
89 MCDI_HEADER_RESYNC, 1,
90 MCDI_HEADER_DATALEN, emrp->emr_in_length,
92 MCDI_HEADER_RESPONSE, 0,
93 MCDI_HEADER_XFLAGS, xflags);
94 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_TRUE);
96 #if EFSYS_OPT_MCDI_LOGGING
97 if (emtp->emt_logger != NULL) {
98 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST,
100 emrp->emr_in_buf, emrp->emr_in_length);
102 #endif /* EFSYS_OPT_MCDI_LOGGING */
104 /* Construct the payload */
105 for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) {
106 memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos),
107 MIN(sizeof (dword), emrp->emr_in_length - pos));
108 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM,
109 pdur + 1 + (pos >> 2), &dword, B_FALSE);
112 /* Ring the doorbell */
113 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xd004be11);
114 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, dbr, &dword, B_FALSE);
118 siena_mcdi_request_copyout(
120 __in efx_mcdi_req_t *emrp)
122 #if EFSYS_OPT_MCDI_LOGGING
123 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
126 size_t bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
128 /* Copy payload out if caller supplied buffer */
129 if (emrp->emr_out_buf != NULL) {
130 siena_mcdi_read_response(enp, emrp->emr_out_buf,
131 sizeof (efx_dword_t), bytes);
134 #if EFSYS_OPT_MCDI_LOGGING
135 if (emtp->emt_logger != NULL) {
136 siena_mcdi_read_response(enp, &hdr, 0, sizeof (hdr));
138 emtp->emt_logger(emtp->emt_context,
139 EFX_LOG_MCDI_RESPONSE,
141 emrp->emr_out_buf, bytes);
143 #endif /* EFSYS_OPT_MCDI_LOGGING */
147 siena_mcdi_poll_reboot(
150 #ifndef EFX_GRACEFUL_MC_REBOOT
152 * This function is not being used properly.
153 * Until its callers are fixed, it should always return 0.
155 _NOTE(ARGUNUSED(enp))
158 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
159 unsigned int rebootr;
163 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
164 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
165 rebootr = SIENA_MCDI_STATUS(emip);
167 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
168 value = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
173 EFX_ZERO_DWORD(dword);
174 EFX_BAR_TBL_WRITED(enp, FR_CZ_MC_TREG_SMEM, rebootr, &dword, B_FALSE);
176 if (value == MC_STATUS_DWORD_ASSERT)
183 extern __checkReturn boolean_t
184 siena_mcdi_poll_response(
187 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
191 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
192 pdur = SIENA_MCDI_PDU(emip);
194 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM, pdur, &hdr, B_FALSE);
195 return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
199 siena_mcdi_read_response(
205 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
210 EFSYS_ASSERT(emip->emi_port == 1 || emip->emi_port == 2);
211 pdur = SIENA_MCDI_PDU(emip);
213 for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) {
214 EFX_BAR_TBL_READD(enp, FR_CZ_MC_TREG_SMEM,
215 pdur + ((offset + pos) >> 2), &data, B_FALSE);
216 memcpy((uint8_t *)bufferp + pos, &data,
217 MIN(sizeof (data), length - pos));
221 __checkReturn efx_rc_t
224 __in const efx_mcdi_transport_t *mtp)
226 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
228 unsigned int portnum;
231 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
233 /* Determine the port number to use for MCDI */
234 EFX_BAR_READO(enp, FR_AZ_CS_DEBUG_REG, &oword);
235 portnum = EFX_OWORD_FIELD(oword, FRF_CZ_CS_PORT_NUM);
238 /* Presumably booted from ROM; only MCDI port 1 will work */
240 } else if (portnum <= 2) {
241 emip->emi_port = portnum;
247 /* Siena BootROM and firmware only support MCDIv1 */
248 emip->emi_max_version = 1;
251 * Wipe the atomic reboot status so subsequent MCDI requests succeed.
252 * BOOT_STATUS is preserved so eno_nic_probe() can boot out of the
255 (void) siena_mcdi_poll_reboot(enp);
260 EFSYS_PROBE1(fail1, efx_rc_t, rc);
271 __checkReturn efx_rc_t
272 siena_mcdi_feature_supported(
274 __in efx_mcdi_feature_id_t id,
275 __out boolean_t *supportedp)
279 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
282 case EFX_MCDI_FEATURE_FW_UPDATE:
283 case EFX_MCDI_FEATURE_LINK_CONTROL:
284 case EFX_MCDI_FEATURE_MACADDR_CHANGE:
285 case EFX_MCDI_FEATURE_MAC_SPOOFING:
286 *supportedp = B_TRUE;
297 EFSYS_PROBE1(fail1, efx_rc_t, rc);
302 #endif /* EFSYS_OPT_SIENA && EFSYS_OPT_MCDI */