1/*-
2 * Copyright (c) 2012-2016 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 <sys/cdefs.h>
32__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/ef10_mcdi.c 311496 2017-01-06 07:32:19Z arybchik $");
33
34#include "efx.h"
35#include "efx_impl.h"
36
37
38#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
39
40#if EFSYS_OPT_MCDI
41
42#ifndef WITH_MCDI_V2
43#error "WITH_MCDI_V2 required for EF10 MCDIv2 commands."
44#endif
45
46
47	__checkReturn	efx_rc_t
48ef10_mcdi_init(
49	__in		efx_nic_t *enp,
50	__in		const efx_mcdi_transport_t *emtp)
51{
52	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
53	efsys_mem_t *esmp = emtp->emt_dma_mem;
54	efx_dword_t dword;
55	efx_rc_t rc;
56
57	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
58		    enp->en_family == EFX_FAMILY_MEDFORD);
59	EFSYS_ASSERT(enp->en_features & EFX_FEATURE_MCDI_DMA);
60
61	/*
62	 * All EF10 firmware supports MCDIv2 and MCDIv1.
63	 * Medford BootROM supports MCDIv2 and MCDIv1.
64	 * Huntington BootROM supports MCDIv1 only.
65	 */
66	emip->emi_max_version = 2;
67
68	/* A host DMA buffer is required for EF10 MCDI */
69	if (esmp == NULL) {
70		rc = EINVAL;
71		goto fail1;
72	}
73
74	/*
75	 * Ensure that the MC doorbell is in a known state before issuing MCDI
76	 * commands. The recovery algorithm requires that the MC command buffer
77	 * must be 256 byte aligned. See bug24769.
78	 */
79	if ((EFSYS_MEM_ADDR(esmp) & 0xFF) != 0) {
80		rc = EINVAL;
81		goto fail2;
82	}
83	EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 1);
84	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
85
86	/* Save initial MC reboot status */
87	(void) ef10_mcdi_poll_reboot(enp);
88
89	/* Start a new epoch (allow fresh MCDI requests to succeed) */
90	efx_mcdi_new_epoch(enp);
91
92	return (0);
93
94fail2:
95	EFSYS_PROBE(fail2);
96fail1:
97	EFSYS_PROBE1(fail1, efx_rc_t, rc);
98
99	return (rc);
100}
101
102			void
103ef10_mcdi_fini(
104	__in		efx_nic_t *enp)
105{
106	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
107
108	emip->emi_new_epoch = B_FALSE;
109}
110
111/*
112 * In older firmware all commands are processed in a single thread, so a long
113 * running command for one PCIe function can block processing for another
114 * function (see bug 61269).
115 *
116 * In newer firmware that supports multithreaded MCDI processing, we can extend
117 * the timeout for long-running requests which we know firmware may choose to
118 * process in a background thread.
119 */
120#define	EF10_MCDI_CMD_TIMEOUT_US	(10 * 1000 * 1000)
121#define	EF10_MCDI_CMD_LONG_TIMEOUT_US	(60 * 1000 * 1000)
122
123			void
124ef10_mcdi_get_timeout(
125	__in		efx_nic_t *enp,
126	__in		efx_mcdi_req_t *emrp,
127	__out		uint32_t *timeoutp)
128{
129	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
130
131	switch (emrp->emr_cmd) {
132	case MC_CMD_POLL_BIST:
133	case MC_CMD_NVRAM_ERASE:
134	case MC_CMD_LICENSING_V3:
135	case MC_CMD_NVRAM_UPDATE_FINISH:
136		if (encp->enc_fw_verified_nvram_update_required != B_FALSE) {
137			/*
138			 * Potentially longer running commands, which firmware
139			 * may choose to process in a background thread.
140			 */
141			*timeoutp = EF10_MCDI_CMD_LONG_TIMEOUT_US;
142			break;
143		}
144		/* FALLTHRU */
145	default:
146		*timeoutp = EF10_MCDI_CMD_TIMEOUT_US;
147		break;
148	}
149}
150
151			void
152ef10_mcdi_send_request(
153	__in			efx_nic_t *enp,
154	__in_bcount(hdr_len)	void *hdrp,
155	__in			size_t hdr_len,
156	__in_bcount(sdu_len)	void *sdup,
157	__in			size_t sdu_len)
158{
159	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
160	efsys_mem_t *esmp = emtp->emt_dma_mem;
161	efx_dword_t dword;
162	unsigned int pos;
163
164	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
165		    enp->en_family == EFX_FAMILY_MEDFORD);
166
167	/* Write the header */
168	for (pos = 0; pos < hdr_len; pos += sizeof (efx_dword_t)) {
169		dword = *(efx_dword_t *)((uint8_t *)hdrp + pos);
170		EFSYS_MEM_WRITED(esmp, pos, &dword);
171	}
172
173	/* Write the payload */
174	for (pos = 0; pos < sdu_len; pos += sizeof (efx_dword_t)) {
175		dword = *(efx_dword_t *)((uint8_t *)sdup + pos);
176		EFSYS_MEM_WRITED(esmp, hdr_len + pos, &dword);
177	}
178
179	/* Guarantee ordering of memory (MCDI request) and PIO (MC doorbell) */
180	EFSYS_DMA_SYNC_FOR_DEVICE(esmp, 0, hdr_len + sdu_len);
181	EFSYS_PIO_WRITE_BARRIER();
182
183	/* Ring the doorbell to post the command DMA address to the MC */
184	EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
185	    EFSYS_MEM_ADDR(esmp) >> 32);
186	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_LWRD_REG, &dword, B_FALSE);
187
188	EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0,
189	    EFSYS_MEM_ADDR(esmp) & 0xffffffff);
190	EFX_BAR_WRITED(enp, ER_DZ_MC_DB_HWRD_REG, &dword, B_FALSE);
191}
192
193	__checkReturn	boolean_t
194ef10_mcdi_poll_response(
195	__in		efx_nic_t *enp)
196{
197	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
198	efsys_mem_t *esmp = emtp->emt_dma_mem;
199	efx_dword_t hdr;
200
201	EFSYS_MEM_READD(esmp, 0, &hdr);
202	EFSYS_MEM_READ_BARRIER();
203
204	return (EFX_DWORD_FIELD(hdr, MCDI_HEADER_RESPONSE) ? B_TRUE : B_FALSE);
205}
206
207			void
208ef10_mcdi_read_response(
209	__in			efx_nic_t *enp,
210	__out_bcount(length)	void *bufferp,
211	__in			size_t offset,
212	__in			size_t length)
213{
214	const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp;
215	efsys_mem_t *esmp = emtp->emt_dma_mem;
216	unsigned int pos;
217	efx_dword_t data;
218
219	for (pos = 0; pos < length; pos += sizeof (efx_dword_t)) {
220		EFSYS_MEM_READD(esmp, offset + pos, &data);
221		memcpy((uint8_t *)bufferp + pos, &data,
222		    MIN(sizeof (data), length - pos));
223	}
224}
225
226			efx_rc_t
227ef10_mcdi_poll_reboot(
228	__in		efx_nic_t *enp)
229{
230	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
231	efx_dword_t dword;
232	uint32_t old_status;
233	uint32_t new_status;
234	efx_rc_t rc;
235
236	old_status = emip->emi_mc_reboot_status;
237
238	/* Update MC reboot status word */
239	EFX_BAR_TBL_READD(enp, ER_DZ_BIU_MC_SFT_STATUS_REG, 0, &dword, B_FALSE);
240	new_status = dword.ed_u32[0];
241
242	/* MC has rebooted if the value has changed */
243	if (new_status != old_status) {
244		emip->emi_mc_reboot_status = new_status;
245
246		/*
247		 * FIXME: Ignore detected MC REBOOT for now.
248		 *
249		 * The Siena support for checking for MC reboot from status
250		 * flags is broken - see comments in siena_mcdi_poll_reboot().
251		 * As the generic MCDI code is shared the EF10 reboot
252		 * detection suffers similar problems.
253		 *
254		 * Do not report an error when the boot status changes until
255		 * this can be handled by common code drivers (and reworked to
256		 * support Siena too).
257		 */
258		_NOTE(CONSTANTCONDITION)
259		if (B_FALSE) {
260			rc = EIO;
261			goto fail1;
262		}
263	}
264
265	return (0);
266
267fail1:
268	EFSYS_PROBE1(fail1, efx_rc_t, rc);
269
270	return (rc);
271}
272
273	__checkReturn	efx_rc_t
274ef10_mcdi_feature_supported(
275	__in		efx_nic_t *enp,
276	__in		efx_mcdi_feature_id_t id,
277	__out		boolean_t *supportedp)
278{
279	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
280	uint32_t privilege_mask = encp->enc_privilege_mask;
281	efx_rc_t rc;
282
283	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
284		    enp->en_family == EFX_FAMILY_MEDFORD);
285
286	/*
287	 * Use privilege mask state at MCDI attach.
288	 */
289
290	switch (id) {
291	case EFX_MCDI_FEATURE_FW_UPDATE:
292		/*
293		 * Admin privilege must be used prior to introduction of
294		 * specific flag.
295		 */
296		*supportedp =
297		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
298		break;
299	case EFX_MCDI_FEATURE_LINK_CONTROL:
300		/*
301		 * Admin privilege used prior to introduction of
302		 * specific flag.
303		 */
304		*supportedp =
305		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, LINK) ||
306		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
307		break;
308	case EFX_MCDI_FEATURE_MACADDR_CHANGE:
309		/*
310		 * Admin privilege must be used prior to introduction of
311		 * mac spoofing privilege (at v4.6), which is used up to
312		 * introduction of change mac spoofing privilege (at v4.7)
313		 */
314		*supportedp =
315		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, CHANGE_MAC) ||
316		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
317		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
318		break;
319	case EFX_MCDI_FEATURE_MAC_SPOOFING:
320		/*
321		 * Admin privilege must be used prior to introduction of
322		 * mac spoofing privilege (at v4.6), which is used up to
323		 * introduction of mac spoofing TX privilege (at v4.7)
324		 */
325		*supportedp =
326		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING_TX) ||
327		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, MAC_SPOOFING) ||
328		    EFX_MCDI_HAVE_PRIVILEGE(privilege_mask, ADMIN);
329		break;
330	default:
331		rc = ENOTSUP;
332		goto fail1;
333	}
334
335	return (0);
336
337fail1:
338	EFSYS_PROBE1(fail1, efx_rc_t, rc);
339
340	return (rc);
341}
342
343#endif	/* EFSYS_OPT_MCDI */
344
345#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
346