ef10_mcdi.c revision 291436
1283514Sarybchik/*-
2283514Sarybchik * Copyright (c) 2012-2015 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4283514Sarybchik *
5283514Sarybchik * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7283514Sarybchik *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29283514Sarybchik */
30283514Sarybchik
31283514Sarybchik#include <sys/cdefs.h>
32283514Sarybchik__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/hunt_mcdi.c 291436 2015-11-29 05:42:49Z arybchik $");
33283514Sarybchik
34283514Sarybchik#include "efsys.h"
35283514Sarybchik#include "efx.h"
36283514Sarybchik#include "efx_impl.h"
37283514Sarybchik
38283514Sarybchik
39283514Sarybchik#if EFSYS_OPT_HUNTINGTON
40283514Sarybchik
41283514Sarybchik#if EFSYS_OPT_MCDI
42283514Sarybchik
43283514Sarybchik#ifndef WITH_MCDI_V2
44283514Sarybchik#error "WITH_MCDI_V2 required for Huntington MCDIv2 commands."
45283514Sarybchik#endif
46283514Sarybchik
47283514Sarybchiktypedef enum efx_mcdi_header_type_e {
48283514Sarybchik	EFX_MCDI_HEADER_TYPE_V1, /* MCDIv0 (BootROM), MCDIv1 commands */
49283514Sarybchik	EFX_MCDI_HEADER_TYPE_V2, /* MCDIv2 commands */
50283514Sarybchik} efx_mcdi_header_type_t;
51283514Sarybchik
52283514Sarybchik/*
53283514Sarybchik * Return the header format to use for sending an MCDI request.
54283514Sarybchik *
55283514Sarybchik * An MCDIv1 (Siena compatible) command should use MCDIv2 encapsulation if the
56283514Sarybchik * request input buffer or response output buffer are too large for the MCDIv1
57283514Sarybchik * format. An MCDIv2 command must always be sent using MCDIv2 encapsulation.
58283514Sarybchik */
59283514Sarybchik#define	EFX_MCDI_HEADER_TYPE(_cmd, _length)				\
60283514Sarybchik	((((_cmd) & ~EFX_MASK32(MCDI_HEADER_CODE)) ||			\
61283514Sarybchik	((_length) & ~EFX_MASK32(MCDI_HEADER_DATALEN)))	?		\
62283514Sarybchik	EFX_MCDI_HEADER_TYPE_V2	: EFX_MCDI_HEADER_TYPE_V1)
63283514Sarybchik
64283514Sarybchik
65283514Sarybchik/*
66283514Sarybchik * MCDI Header NOT_EPOCH flag
67283514Sarybchik * ==========================
68283514Sarybchik * A new epoch begins at initial startup or after an MC reboot, and defines when
69283514Sarybchik * the MC should reject stale MCDI requests.
70283514Sarybchik *
71283514Sarybchik * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all
72283514Sarybchik * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1.
73283514Sarybchik *
74283514Sarybchik * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a
75283514Sarybchik * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0.
76283514Sarybchik */
77283514Sarybchik
78283514Sarybchik
79291436Sarybchik	__checkReturn	efx_rc_t
80283514Sarybchikhunt_mcdi_init(
81283514Sarybchik	__in		efx_nic_t *enp,
82283514Sarybchik	__in		const efx_mcdi_transport_t *emtp)
83283514Sarybchik{
84283514Sarybchik	efsys_mem_t *esmp = emtp->emt_dma_mem;
85283514Sarybchik	efx_dword_t dword;
86291436Sarybchik	efx_rc_t rc;
87283514Sarybchik
88283514Sarybchik	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON);
89283514Sarybchik	EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
90283514Sarybchik
91283514Sarybchik	/* A host DMA buffer is required for Huntington MCDI */
92283514Sarybchik	if (esmp == NULL) {
93283514Sarybchik		rc = EINVAL;
94283514Sarybchik		goto fail1;
95283514Sarybchik	}
96283514Sarybchik
97283514Sarybchik	/*
98283514Sarybchik	 * Ensure that the MC doorbell is in a known state before issuing MCDI
99283514Sarybchik	 * commands. The recovery algorithm requires that the MC command buffer
100283514Sarybchik	 * must be 256 byte aligned. See bug24769.
101283514Sarybchik	 */
102283514Sarybchik	if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
103283514Sarybchik		rc = EINVAL;
104283514Sarybchik		goto fail2;
105283514Sarybchik	}
106283514Sarybchik	EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
107283514Sarybchik	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
108283514Sarybchik
109283514Sarybchik	/* Save initial MC reboot status */
110283514Sarybchik	(void) hunt_mcdi_poll_reboot(enp);
111283514Sarybchik
112283514Sarybchik	/* Start a new epoch (allow fresh MCDI requests to succeed) */
113283514Sarybchik	efx_mcdi_new_epoch(enp);
114283514Sarybchik
115283514Sarybchik	return (0);
116283514Sarybchik
117283514Sarybchikfail2:
118283514Sarybchik	EFSYS_PROBE(fail2);
119283514Sarybchikfail1:
120291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
121283514Sarybchik
122283514Sarybchik	return (rc);
123283514Sarybchik}
124283514Sarybchik
125283514Sarybchik			void
126283514Sarybchikhunt_mcdi_fini(
127283514Sarybchik	__in		efx_nic_t *enp)
128283514Sarybchik{
129283514Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
130283514Sarybchik
131283514Sarybchik	emip->emi_new_epoch = B_FALSE;
132283514Sarybchik}
133283514Sarybchik
134283514Sarybchik			void
135283514Sarybchikhunt_mcdi_request_copyin(
136283514Sarybchik	__in		efx_nic_t *enp,
137283514Sarybchik	__in		efx_mcdi_req_t *emrp,
138283514Sarybchik	__in		unsigned int seq,
139283514Sarybchik	__in		boolean_t ev_cpl,
140283514Sarybchik	__in		boolean_t new_epoch)
141283514Sarybchik{
142283514Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
143283514Sarybchik	efsys_mem_t *esmp = emtp->emt_dma_mem;
144283514Sarybchik	efx_mcdi_header_type_t hdr_type;
145283514Sarybchik	efx_dword_t dword;
146283514Sarybchik	unsigned int xflags;
147283514Sarybchik	unsigned int pos;
148283514Sarybchik	size_t offset;
149283514Sarybchik
150283514Sarybchik	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
151283514Sarybchik
152283514Sarybchik	xflags = 0;
153283514Sarybchik	if (ev_cpl)
154283514Sarybchik		xflags |= MCDI_HEADER_XFLAGS_EVREQ;
155283514Sarybchik
156283514Sarybchik	offset = 0;
157283514Sarybchik
158283514Sarybchik	hdr_type = EFX_MCDI_HEADER_TYPE(emrp->emr_cmd,
159283514Sarybchik	    MAX(emrp->emr_in_length, emrp->emr_out_length));
160283514Sarybchik
161283514Sarybchik	if (hdr_type == EFX_MCDI_HEADER_TYPE_V2) {
162283514Sarybchik		/* Construct MCDI v2 header */
163283514Sarybchik		EFX_POPULATE_DWORD_8(dword,
164283514Sarybchik		    MCDI_HEADER_CODE, MC_CMD_V2_EXTN,
165283514Sarybchik		    MCDI_HEADER_RESYNC, 1,
166283514Sarybchik		    MCDI_HEADER_DATALEN, 0,
167283514Sarybchik		    MCDI_HEADER_SEQ, seq,
168283514Sarybchik		    MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
169283514Sarybchik		    MCDI_HEADER_ERROR, 0,
170283514Sarybchik		    MCDI_HEADER_RESPONSE, 0,
171283514Sarybchik		    MCDI_HEADER_XFLAGS, xflags);
172283514Sarybchik		EFSYS_MEM_WRITED(esmp, offset, &dword);
173283514Sarybchik		offset += sizeof (dword);
174283514Sarybchik
175283514Sarybchik		EFX_POPULATE_DWORD_2(dword,
176283514Sarybchik		    MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd,
177283514Sarybchik		    MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length);
178283514Sarybchik		EFSYS_MEM_WRITED(esmp, offset, &dword);
179283514Sarybchik		offset += sizeof (dword);
180283514Sarybchik	} else {
181283514Sarybchik		/* Construct MCDI v1 header */
182283514Sarybchik		EFX_POPULATE_DWORD_8(dword,
183283514Sarybchik		    MCDI_HEADER_CODE, emrp->emr_cmd,
184283514Sarybchik		    MCDI_HEADER_RESYNC, 1,
185283514Sarybchik		    MCDI_HEADER_DATALEN, emrp->emr_in_length,
186283514Sarybchik		    MCDI_HEADER_SEQ, seq,
187283514Sarybchik		    MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1,
188283514Sarybchik		    MCDI_HEADER_ERROR, 0,
189283514Sarybchik		    MCDI_HEADER_RESPONSE, 0,
190283514Sarybchik		    MCDI_HEADER_XFLAGS, xflags);
191283514Sarybchik		EFSYS_MEM_WRITED(esmp, offset, &dword);
192283514Sarybchik		offset += sizeof (dword);
193283514Sarybchik	}
194283514Sarybchik
195283514Sarybchik	/* Construct the payload */
196283514Sarybchik	for (pos = 0; pos < emrp->emr_in_length; pos += sizeof (efx_dword_t)) {
197283514Sarybchik		memcpy(&dword, MCDI_IN(*emrp, efx_dword_t, pos),
198283514Sarybchik		    MIN(sizeof (dword), emrp->emr_in_length - pos));
199283514Sarybchik		EFSYS_MEM_WRITED(esmp, offset + pos, &dword);
200283514Sarybchik	}
201283514Sarybchik
202283514Sarybchik	/* Ring the doorbell to post the command DMA address to the MC */
203283514Sarybchik	EFSYS_ASSERT((EFSYS_MEM_ADDR(esmp) & 0xFF) == 0);
204283514Sarybchik
205283514Sarybchik	/* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
206283514Sarybchik	EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, offset + emrp->emr_in_length);
207283514Sarybchik	EFSYS_PIO_WRITE_BARRIER();
208283514Sarybchik
209283514Sarybchik	EFX_POPULATE_DWORD_1(dword,
210283514Sarybchik	    EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) >> 32);
211283514Sarybchik	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
212283514Sarybchik
213283514Sarybchik	EFX_POPULATE_DWORD_1(dword,
214283514Sarybchik	    EFX_DWORD_0, EFSYS_MEM_ADDR(esmp) & 0xffffffff);
215283514Sarybchik	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
216283514Sarybchik}
217283514Sarybchik
218283514Sarybchik			void
219283514Sarybchikhunt_mcdi_request_copyout(
220283514Sarybchik	__in		efx_nic_t *enp,
221283514Sarybchik	__in		efx_mcdi_req_t *emrp)
222283514Sarybchik{
223283514Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
224283514Sarybchik	efsys_mem_t *esmp = emtp->emt_dma_mem;
225283514Sarybchik	unsigned int pos;
226283514Sarybchik	unsigned int offset;
227283514Sarybchik	efx_dword_t hdr;
228283514Sarybchik	efx_dword_t hdr2;
229283514Sarybchik	efx_dword_t data;
230283514Sarybchik	size_t bytes;
231283514Sarybchik
232283514Sarybchik	if (emrp->emr_out_buf == NULL)
233283514Sarybchik		return;
234283514Sarybchik
235283514Sarybchik	/* Read the command header to detect MCDI response format */
236283514Sarybchik	EFSYS_MEM_READD(esmp, 0, &hdr);
237283514Sarybchik	if (EFX_DWORD_FIELD(hdr, MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
238283514Sarybchik		offset = 2 * sizeof (efx_dword_t);
239283514Sarybchik
240283514Sarybchik		/*
241283514Sarybchik		 * Read the actual payload length. The length given in the event
242283514Sarybchik		 * is only correct for responses with the V1 format.
243283514Sarybchik		 */
244283514Sarybchik		EFSYS_MEM_READD(esmp, sizeof (efx_dword_t), &hdr2);
245283514Sarybchik		emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr2,
246283514Sarybchik					    MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
247283514Sarybchik	} else {
248283514Sarybchik		offset = sizeof (efx_dword_t);
249283514Sarybchik	}
250283514Sarybchik
251283514Sarybchik	/* Copy payload out into caller supplied buffer */
252283514Sarybchik	bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length);
253283514Sarybchik	for (pos = 0; pos < bytes; pos += sizeof (efx_dword_t)) {
254283514Sarybchik		EFSYS_MEM_READD(esmp, offset + pos, &data);
255283514Sarybchik		memcpy(MCDI_OUT(*emrp, efx_dword_t, pos), &data,
256283514Sarybchik		    MIN(sizeof (data), bytes - pos));
257283514Sarybchik	}
258283514Sarybchik}
259283514Sarybchik
260283514Sarybchik	__checkReturn	boolean_t
261283514Sarybchikhunt_mcdi_request_poll(
262283514Sarybchik	__in		efx_nic_t *enp)
263283514Sarybchik{
264283514Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
265283514Sarybchik	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
266283514Sarybchik	efsys_mem_t *esmp = emtp->emt_dma_mem;
267283514Sarybchik	efx_mcdi_req_t *emrp;
268283514Sarybchik	efx_dword_t dword;
269283514Sarybchik	unsigned int seq;
270283514Sarybchik	unsigned int cmd;
271283514Sarybchik	unsigned int length;
272283514Sarybchik	size_t offset;
273283514Sarybchik	int state;
274291436Sarybchik	efx_rc_t rc;
275283514Sarybchik
276283514Sarybchik	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
277283514Sarybchik
278283514Sarybchik	/* Serialise against post-watchdog efx_mcdi_ev* */
279283514Sarybchik	EFSYS_LOCK(enp->en_eslp, state);
280283514Sarybchik
281283514Sarybchik	EFSYS_ASSERT(emip->emi_pending_req != NULL);
282283514Sarybchik	EFSYS_ASSERT(!emip->emi_ev_cpl);
283283514Sarybchik	emrp = emip->emi_pending_req;
284283514Sarybchik
285283514Sarybchik	offset = 0;
286283514Sarybchik
287283514Sarybchik	/* Read the command header */
288283514Sarybchik	EFSYS_MEM_READD(esmp, offset, &dword);
289283514Sarybchik	offset += sizeof (efx_dword_t);
290283514Sarybchik	if (EFX_DWORD_FIELD(dword, MCDI_HEADER_RESPONSE) == 0) {
291283514Sarybchik		EFSYS_UNLOCK(enp->en_eslp, state);
292283514Sarybchik		return (B_FALSE);
293283514Sarybchik	}
294283514Sarybchik	if (EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) {
295283514Sarybchik		efx_dword_t dword2;
296283514Sarybchik
297283514Sarybchik		EFSYS_MEM_READD(esmp, offset, &dword2);
298283514Sarybchik		offset += sizeof (efx_dword_t);
299283514Sarybchik
300283514Sarybchik		cmd = EFX_DWORD_FIELD(dword2, MC_CMD_V2_EXTN_IN_EXTENDED_CMD);
301283514Sarybchik		length = EFX_DWORD_FIELD(dword2, MC_CMD_V2_EXTN_IN_ACTUAL_LEN);
302283514Sarybchik	} else {
303283514Sarybchik		cmd = EFX_DWORD_FIELD(dword, MCDI_HEADER_CODE);
304283514Sarybchik		length = EFX_DWORD_FIELD(dword, MCDI_HEADER_DATALEN);
305283514Sarybchik	}
306283514Sarybchik
307283514Sarybchik	/* Request complete */
308283514Sarybchik	emip->emi_pending_req = NULL;
309283514Sarybchik	seq = (emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ);
310283514Sarybchik
311283514Sarybchik	/* Check for synchronous reboot */
312283514Sarybchik	if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR) != 0 && length == 0) {
313283514Sarybchik		/* The MC has rebooted since the request was sent. */
314283514Sarybchik		EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US);
315283514Sarybchik		hunt_mcdi_poll_reboot(enp);
316283514Sarybchik
317283514Sarybchik		EFSYS_UNLOCK(enp->en_eslp, state);
318283514Sarybchik		rc = EIO;
319283514Sarybchik		goto fail1;
320283514Sarybchik	}
321283514Sarybchik
322283514Sarybchik	/* Ensure stale MCDI requests fail after an MC reboot. */
323283514Sarybchik	emip->emi_new_epoch = B_FALSE;
324283514Sarybchik
325283514Sarybchik	EFSYS_UNLOCK(enp->en_eslp, state);
326283514Sarybchik
327283514Sarybchik	/* Check that the returned data is consistent */
328283514Sarybchik	if (cmd != emrp->emr_cmd ||
329283514Sarybchik	    EFX_DWORD_FIELD(dword, MCDI_HEADER_SEQ) != seq) {
330283514Sarybchik		/* Response is for a different request */
331283514Sarybchik		rc = EIO;
332283514Sarybchik		goto fail2;
333283514Sarybchik	}
334283514Sarybchik	if (EFX_DWORD_FIELD(dword, MCDI_HEADER_ERROR)) {
335283514Sarybchik		efx_dword_t errdword;
336283514Sarybchik		int errcode;
337283514Sarybchik		int argnum;
338283514Sarybchik
339283514Sarybchik		/* Read error code (and arg num for MCDI v2 commands) */
340283514Sarybchik		EFSYS_MEM_READD(esmp, offset + MC_CMD_ERR_CODE_OFST, &errdword);
341283514Sarybchik		errcode = EFX_DWORD_FIELD(errdword, EFX_DWORD_0);
342283514Sarybchik
343283514Sarybchik		EFSYS_MEM_READD(esmp, offset + MC_CMD_ERR_ARG_OFST, &errdword);
344283514Sarybchik		argnum = EFX_DWORD_FIELD(errdword, EFX_DWORD_0);
345283514Sarybchik
346283514Sarybchik		rc = efx_mcdi_request_errcode(errcode);
347283514Sarybchik		if (!emrp->emr_quiet) {
348283514Sarybchik			EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd,
349283514Sarybchik			    int, errcode, int, argnum);
350283514Sarybchik		}
351283514Sarybchik		goto fail3;
352283514Sarybchik
353283514Sarybchik	} else {
354283514Sarybchik		emrp->emr_out_length_used = length;
355283514Sarybchik		emrp->emr_rc = 0;
356283514Sarybchik		hunt_mcdi_request_copyout(enp, emrp);
357283514Sarybchik	}
358283514Sarybchik
359283514Sarybchik	goto out;
360283514Sarybchik
361283514Sarybchikfail3:
362283514Sarybchik	if (!emrp->emr_quiet)
363283514Sarybchik		EFSYS_PROBE(fail3);
364283514Sarybchikfail2:
365283514Sarybchik	if (!emrp->emr_quiet)
366283514Sarybchik		EFSYS_PROBE(fail2);
367283514Sarybchikfail1:
368283514Sarybchik	if (!emrp->emr_quiet)
369291436Sarybchik		EFSYS_PROBE1(fail1, efx_rc_t, rc);
370283514Sarybchik
371283514Sarybchik	/* Fill out error state */
372283514Sarybchik	emrp->emr_rc = rc;
373283514Sarybchik	emrp->emr_out_length_used = 0;
374283514Sarybchik
375283514Sarybchik	/* Reboot/Assertion */
376283514Sarybchik	if (rc == EIO || rc == EINTR)
377283514Sarybchik		efx_mcdi_raise_exception(enp, emrp, rc);
378283514Sarybchik
379283514Sarybchikout:
380283514Sarybchik	return (B_TRUE);
381283514Sarybchik}
382283514Sarybchik
383291436Sarybchik			efx_rc_t
384283514Sarybchikhunt_mcdi_poll_reboot(
385283514Sarybchik	__in		efx_nic_t *enp)
386283514Sarybchik{
387283514Sarybchik	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
388283514Sarybchik	efx_dword_t dword;
389283514Sarybchik	uint32_t old_status;
390283514Sarybchik	uint32_t new_status;
391291436Sarybchik	efx_rc_t rc;
392283514Sarybchik
393283514Sarybchik	old_status = emip->emi_mc_reboot_status;
394283514Sarybchik
395283514Sarybchik	/* Update MC reboot status word */
396283514Sarybchik	EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE);
397283514Sarybchik	new_status = dword.ed_u32[0];
398283514Sarybchik
399283514Sarybchik	/* MC has rebooted if the value has changed */
400283514Sarybchik	if (new_status != old_status) {
401283514Sarybchik		emip->emi_mc_reboot_status = new_status;
402283514Sarybchik
403283514Sarybchik		/*
404283514Sarybchik		 * FIXME: Ignore detected MC REBOOT for now.
405283514Sarybchik		 *
406283514Sarybchik		 * The Siena support for checking for MC reboot from status
407283514Sarybchik		 * flags is broken - see comments in siena_mcdi_poll_reboot().
408283514Sarybchik		 * As the generic MCDI code is shared the Huntington reboot
409283514Sarybchik		 * detection suffers similar problems.
410283514Sarybchik		 *
411283514Sarybchik		 * Do not report an error when the boot status changes until
412283514Sarybchik		 * this can be handled by common code drivers (and reworked to
413283514Sarybchik		 * support Siena too).
414283514Sarybchik		 */
415283514Sarybchik		if (B_FALSE) {
416283514Sarybchik			rc = EIO;
417283514Sarybchik			goto fail1;
418283514Sarybchik		}
419283514Sarybchik	}
420283514Sarybchik
421283514Sarybchik	return (0);
422283514Sarybchik
423283514Sarybchikfail1:
424291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
425283514Sarybchik
426283514Sarybchik	return (rc);
427283514Sarybchik}
428283514Sarybchik
429291436Sarybchik	__checkReturn	efx_rc_t
430283514Sarybchikhunt_mcdi_fw_update_supported(
431283514Sarybchik	__in		efx_nic_t *enp,
432283514Sarybchik	__out		boolean_t *supportedp)
433283514Sarybchik{
434283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
435283514Sarybchik
436283514Sarybchik	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
437283514Sarybchik
438283514Sarybchik	/* use privilege mask state at MCDI attach */
439283514Sarybchik	*supportedp = (encp->enc_privilege_mask &
440283514Sarybchik	    MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN)
441283514Sarybchik	    == MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN;
442283514Sarybchik
443283514Sarybchik	return (0);
444283514Sarybchik}
445283514Sarybchik
446291436Sarybchik	__checkReturn	efx_rc_t
447283514Sarybchikhunt_mcdi_macaddr_change_supported(
448283514Sarybchik	__in		efx_nic_t *enp,
449283514Sarybchik	__out		boolean_t *supportedp)
450283514Sarybchik{
451283514Sarybchik	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
452283514Sarybchik
453283514Sarybchik	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_HUNTINGTON);
454283514Sarybchik
455283514Sarybchik	/* use privilege mask state at MCDI attach */
456283514Sarybchik	*supportedp = (encp->enc_privilege_mask &
457283514Sarybchik	    MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING)
458283514Sarybchik	    == MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING;
459283514Sarybchik
460283514Sarybchik	return (0);
461283514Sarybchik}
462283514Sarybchik
463283514Sarybchik#endif	/* EFSYS_OPT_MCDI */
464283514Sarybchik
465283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
466