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$");
39 #if EFSYS_OPT_HUNTINGTON
44 #error "WITH_MCDI_V2 required for Huntington MCDIv2 commands."
47 typedef enum efx_mcdi_header_type_e {
48 EFX_MCDI_HEADER_TYPE_V1, /* MCDIv0 (BootROM), MCDIv1 commands */
49 EFX_MCDI_HEADER_TYPE_V2, /* MCDIv2 commands */
50 } efx_mcdi_header_type_t;
53 * Return the header format to use for sending an MCDI request.
55 * An MCDIv1 (Siena compatible) command should use MCDIv2 encapsulation if the
56 * request input buffer or response output buffer are too large for the MCDIv1
57 * format. An MCDIv2 command must always be sent using MCDIv2 encapsulation.
59 #define EFX_MCDI_HEADER_TYPE(_cmd, _length) \
60 ((((_cmd) & ~EFX_MASK32(MCDI_HEADER_CODE)) || \
61 ((_length) & ~EFX_MASK32(MCDI_HEADER_DATALEN))) ? \
62 EFX_MCDI_HEADER_TYPE_V2 : EFX_MCDI_HEADER_TYPE_V1)
66 * MCDI Header NOT_EPOCH flag
67 * ==========================
68 * A new epoch begins at initial startup or after an MC reboot, and defines when
69 * the MC should reject stale MCDI requests.
71 * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
72 * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
74 * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
75 * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
82 __in const efx_mcdi_transport_t *emtp)
84 efsys_mem_t *esmp = emtp->emt_dma_mem;
88 EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
89 EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
91 /* A host DMA buffer is required for Huntington MCDI */
98 * Ensure that the MC doorbell is in a known state before issuing MCDI
99 * commands. The recovery algorithm requires that the MC command buffer
100 * must be 256 byte aligned. See bug24769.
102 if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
106 EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
107 EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
109 /* Save initial MC reboot status */
110 (void) hunt_mcdi_poll_reboot(enp);
112 /* Start a new epoch (allow fresh MCDI requests to succeed) */
113 efx_mcdi_new_epoch(enp);
120 EFSYS_PROBE1(fail1, int, rc);
129 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
131 emip->emi_new_epoch = B_FALSE;
135 hunt_mcdi_request_copyin(
137 __in efx_mcdi_req_t *emrp,
138 __in unsigned int seq,
139 __in boolean_t ev_cpl,
140 __in boolean_t new_epoch)
142 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
143 efsys_mem_t *esmp = emtp->emt_dma_mem;
144 efx_mcdi_header_type_t hdr_type;
150 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
154 xflags |= MCDI_HEADER_XFLAGS_EVREQ;
158 hdr_type = EFX_MCDI_HEADER_TYPE(emrp->emr_cmd,
159 MAX(emrp->emr_in_length, emrp->emr_out_length));
161 if (hdr_type == EFX_MCDI_HEADER_TYPE_V2) {
162 /* Construct MCDI v2 header */
163 EFX_POPULATE_DWORD_8(dword,
164 MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
165 MCDI_HEADER_RESYNC, 1,
166 MCDI_HEADER_DATALEN, 0,
167 MCDI_HEADER_SEQ, seq,
168 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
169 MCDI_HEADER_ERROR, 0,
170 MCDI_HEADER_RESPONSE, 0,
171 MCDI_HEADER_XFLAGS, xflags);
172 EFSYS_MEM_WRITED(esmp, offset, &dword);
173 offset += sizeof (dword);
175 EFX_POPULATE_DWORD_2(dword,
176 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
177 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
178 EFSYS_MEM_WRITED(esmp, offset, &dword);
179 offset += sizeof (dword);
181 /* Construct MCDI v1 header */
182 EFX_POPULATE_DWORD_8(dword,
183 MCDI_HEADER_CODE, emrp->emr_cmd,
184 MCDI_HEADER_RESYNC, 1,
185 MCDI_HEADER_DATALEN, emrp->emr_in_length,
186 MCDI_HEADER_SEQ, seq,
187 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
188 MCDI_HEADER_ERROR, 0,
189 MCDI_HEADER_RESPONSE, 0,
190 MCDI_HEADER_XFLAGS, xflags);
191 EFSYS_MEM_WRITED(esmp, offset, &dword);
192 offset += sizeof (dword);
195 /* Construct the payload */
196 for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) {
197 memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos),
198 MIN(sizeof (dword), emrp->emr_in_length - pos));
199 EFSYS_MEM_WRITED(esmp, offset + pos, &dword);
202 /* Ring the doorbell to post the command DMA address to the MC */
203 EFSYS_ASSERT((EFSYS_MEM_ADDR(esmp) & 0xFF) == 0);
205 /* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
206 EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, offset + emrp->emr_in_length);
207 EFSYS_PIO_WRITE_BARRIER();
209 EFX_POPULATE_DWORD_1(dword,
210 EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32);
211 EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
213 EFX_POPULATE_DWORD_1(dword,
214 EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff);
215 EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
219 hunt_mcdi_request_copyout(
221 __in efx_mcdi_req_t *emrp)
223 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
224 efsys_mem_t *esmp = emtp->emt_dma_mem;
232 if (emrp->emr_out_buf == NULL)
235 /* Read the command header to detect MCDI response format */
236 EFSYS_MEM_READD(esmp, 0, &hdr);
237 if (EFX_DWORD_FIELD(hdr, MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
238 offset = 2 * sizeof (efx_dword_t);
241 * Read the actual payload length. The length given in the event
242 * is only correct for responses with the V1 format.
244 EFSYS_MEM_READD(esmp, sizeof (efx_dword_t), &hdr2);
245 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr2,
246 MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
248 offset = sizeof (efx_dword_t);
251 /* Copy payload out into caller supplied buffer */
252 bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
253 for (pos = 0; pos < bytes; pos += sizeof (efx_dword_t)) {
254 EFSYS_MEM_READD(esmp, offset + pos, &data);
255 memcpy(MCDI_OUT(*emrp, efx_dword_t, pos), &data,
256 MIN(sizeof (data), bytes - pos));
260 __checkReturn boolean_t
261 hunt_mcdi_request_poll(
264 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
265 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
266 efsys_mem_t *esmp = emtp->emt_dma_mem;
267 efx_mcdi_req_t *emrp;
276 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
278 /* Serialise against post-watchdog efx_mcdi_ev* */
279 EFSYS_LOCK(enp->en_eslp, state);
281 EFSYS_ASSERT(emip->emi_pending_req != NULL);
282 EFSYS_ASSERT(!emip->emi_ev_cpl);
283 emrp = emip->emi_pending_req;
287 /* Read the command header */
288 EFSYS_MEM_READD(esmp, offset, &dword);
289 offset += sizeof (efx_dword_t);
290 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_RESPONSE) == 0) {
291 EFSYS_UNLOCK(enp->en_eslp, state);
294 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
297 EFSYS_MEM_READD(esmp, offset, &dword2);
298 offset += sizeof (efx_dword_t);
300 cmd = EFX_DWORD_FIELD(dword2, MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
301 length = EFX_DWORD_FIELD(dword2, MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
303 cmd = EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE);
304 length = EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN);
307 /* Request complete */
308 emip->emi_pending_req = NULL;
309 seq = (emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ);
311 /* Check for synchronous reboot */
312 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR) != 0 && length == 0) {
313 /* The MC has rebooted since the request was sent. */
314 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
315 hunt_mcdi_poll_reboot(enp);
317 EFSYS_UNLOCK(enp->en_eslp, state);
322 /* Ensure stale MCDI requests fail after an MC reboot. */
323 emip->emi_new_epoch = B_FALSE;
325 EFSYS_UNLOCK(enp->en_eslp, state);
327 /* Check that the returned data is consistent */
328 if (cmd != emrp->emr_cmd ||
329 EFX_DWORD_FIELD(dword, MCDI_HEADER_SEQ) != seq) {
330 /* Response is for a different request */
334 if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR)) {
335 efx_dword_t errdword;
339 /* Read error code (and arg num for MCDI v2 commands) */
340 EFSYS_MEM_READD(esmp, offset + MC_CMD_ERR_CODE_OFST, &errdword);
341 errcode = EFX_DWORD_FIELD(errdword, EFX_DWORD_0);
343 EFSYS_MEM_READD(esmp, offset + MC_CMD_ERR_ARG_OFST, &errdword);
344 argnum = EFX_DWORD_FIELD(errdword, EFX_DWORD_0);
346 rc = efx_mcdi_request_errcode(errcode);
347 if (!emrp->emr_quiet) {
348 EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
349 int, errcode, int, argnum);
354 emrp->emr_out_length_used = length;
356 hunt_mcdi_request_copyout(enp, emrp);
362 if (!emrp->emr_quiet)
365 if (!emrp->emr_quiet)
368 if (!emrp->emr_quiet)
369 EFSYS_PROBE1(fail1, int, rc);
371 /* Fill out error state */
373 emrp->emr_out_length_used = 0;
375 /* Reboot/Assertion */
376 if (rc == EIO || rc == EINTR)
377 efx_mcdi_raise_exception(enp, emrp, rc);
384 hunt_mcdi_poll_reboot(
387 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
393 old_status = emip->emi_mc_reboot_status;
395 /* Update MC reboot status word */
396 EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE);
397 new_status = dword.ed_u32[0];
399 /* MC has rebooted if the value has changed */
400 if (new_status != old_status) {
401 emip->emi_mc_reboot_status = new_status;
404 * FIXME: Ignore detected MC REBOOT for now.
406 * The Siena support for checking for MC reboot from status
407 * flags is broken - see comments in siena_mcdi_poll_reboot().
408 * As the generic MCDI code is shared the Huntington reboot
409 * detection suffers similar problems.
411 * Do not report an error when the boot status changes until
412 * this can be handled by common code drivers (and reworked to
413 * support Siena too).
424 EFSYS_PROBE1(fail1, int, rc);
430 hunt_mcdi_fw_update_supported(
432 __out boolean_t *supportedp)
434 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
436 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
438 /* use privilege mask state at MCDI attach */
439 *supportedp = (encp->enc_privilege_mask &
440 MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN)
441 == MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN;
447 hunt_mcdi_macaddr_change_supported(
449 __out boolean_t *supportedp)
451 efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
453 EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
455 /* use privilege mask state at MCDI attach */
456 *supportedp = (encp->enc_privilege_mask &
457 MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING)
458 == MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING;
463 #endif /* EFSYS_OPT_MCDI */
465 #endif /* EFSYS_OPT_HUNTINGTON */