1227569Sphilip/*-
2300607Sarybchik * Copyright (c) 2009-2016 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4227569Sphilip *
5227569Sphilip * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7227569Sphilip *
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.
29227569Sphilip */
30228078Sphilip
31228078Sphilip#include <sys/cdefs.h>
32228078Sphilip__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/siena_nic.c 342445 2018-12-25 07:27:45Z arybchik $");
33228078Sphilip
34227569Sphilip#include "efx.h"
35227569Sphilip#include "efx_impl.h"
36283514Sarybchik#include "mcdi_mon.h"
37227569Sphilip
38227569Sphilip#if EFSYS_OPT_SIENA
39227569Sphilip
40310933Sarybchik#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
41310933Sarybchik
42291436Sarybchikstatic	__checkReturn		efx_rc_t
43227569Sphilipsiena_nic_get_partn_mask(
44227569Sphilip	__in			efx_nic_t *enp,
45227569Sphilip	__out			unsigned int *maskp)
46227569Sphilip{
47227569Sphilip	efx_mcdi_req_t req;
48342445Sarybchik	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_NVRAM_TYPES_IN_LEN,
49342445Sarybchik		MC_CMD_NVRAM_TYPES_OUT_LEN);
50291436Sarybchik	efx_rc_t rc;
51227569Sphilip
52227569Sphilip	req.emr_cmd = MC_CMD_NVRAM_TYPES;
53283514Sarybchik	req.emr_in_buf = payload;
54283514Sarybchik	req.emr_in_length = MC_CMD_NVRAM_TYPES_IN_LEN;
55283514Sarybchik	req.emr_out_buf = payload;
56283514Sarybchik	req.emr_out_length = MC_CMD_NVRAM_TYPES_OUT_LEN;
57227569Sphilip
58227569Sphilip	efx_mcdi_execute(enp, &req);
59227569Sphilip
60227569Sphilip	if (req.emr_rc != 0) {
61227569Sphilip		rc = req.emr_rc;
62227569Sphilip		goto fail1;
63227569Sphilip	}
64227569Sphilip
65227569Sphilip	if (req.emr_out_length_used < MC_CMD_NVRAM_TYPES_OUT_LEN) {
66227569Sphilip		rc = EMSGSIZE;
67227569Sphilip		goto fail2;
68227569Sphilip	}
69227569Sphilip
70227569Sphilip	*maskp = MCDI_OUT_DWORD(req, NVRAM_TYPES_OUT_TYPES);
71227569Sphilip
72227569Sphilip	return (0);
73227569Sphilip
74227569Sphilipfail2:
75227569Sphilip	EFSYS_PROBE(fail2);
76227569Sphilipfail1:
77291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
78227569Sphilip
79227569Sphilip	return (rc);
80227569Sphilip}
81227569Sphilip
82310933Sarybchik#endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */
83310933Sarybchik
84291436Sarybchikstatic	__checkReturn	efx_rc_t
85227569Sphilipsiena_board_cfg(
86227569Sphilip	__in		efx_nic_t *enp)
87227569Sphilip{
88227569Sphilip	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
89283514Sarybchik	uint8_t mac_addr[6];
90283514Sarybchik	efx_dword_t capabilities;
91283514Sarybchik	uint32_t board_type;
92283514Sarybchik	uint32_t nevq, nrxq, ntxq;
93291436Sarybchik	efx_rc_t rc;
94227569Sphilip
95283514Sarybchik	/* External port identifier using one-based port numbering */
96283514Sarybchik	encp->enc_external_port = (uint8_t)enp->en_mcdi.em_emip.emi_port;
97283514Sarybchik
98227569Sphilip	/* Board configuration */
99283514Sarybchik	if ((rc = efx_mcdi_get_board_cfg(enp, &board_type,
100283514Sarybchik		    &capabilities, mac_addr)) != 0)
101227569Sphilip		goto fail1;
102227569Sphilip
103279048Sarybchik	EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr);
104227569Sphilip
105283514Sarybchik	encp->enc_board_type = board_type;
106227569Sphilip
107311016Sarybchik	/*
108311016Sarybchik	 * There is no possibility to determine the number of PFs on Siena
109311016Sarybchik	 * by issuing MCDI request, and it is not an easy task to find the
110311016Sarybchik	 * value based on the board type, so 'enc_hw_pf_count' is set to 1
111311016Sarybchik	 */
112311016Sarybchik	encp->enc_hw_pf_count = 1;
113311016Sarybchik
114279048Sarybchik	/* Additional capabilities */
115279048Sarybchik	encp->enc_clk_mult = 1;
116283514Sarybchik	if (EFX_DWORD_FIELD(capabilities, MC_CMD_CAPABILITIES_TURBO)) {
117279048Sarybchik		enp->en_features |= EFX_FEATURE_TURBO;
118279048Sarybchik
119283514Sarybchik		if (EFX_DWORD_FIELD(capabilities,
120283514Sarybchik			MC_CMD_CAPABILITIES_TURBO_ACTIVE)) {
121279048Sarybchik			encp->enc_clk_mult = 2;
122283514Sarybchik		}
123279048Sarybchik	}
124279048Sarybchik
125279182Sarybchik	encp->enc_evq_timer_quantum_ns =
126279182Sarybchik		EFX_EVQ_SIENA_TIMER_QUANTUM_NS / encp->enc_clk_mult;
127279182Sarybchik	encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns <<
128279182Sarybchik		FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000;
129279048Sarybchik
130283514Sarybchik	/* When hash header insertion is enabled, Siena inserts 16 bytes */
131283514Sarybchik	encp->enc_rx_prefix_size = 16;
132227569Sphilip
133283514Sarybchik	/* Alignment for receive packet DMA buffers */
134283514Sarybchik	encp->enc_rx_buf_align_start = 1;
135283514Sarybchik	encp->enc_rx_buf_align_end = 1;
136227569Sphilip
137283514Sarybchik	/* Alignment for WPTR updates */
138283514Sarybchik	encp->enc_rx_push_align = 1;
139227569Sphilip
140311765Sarybchik	encp->enc_tx_dma_desc_size_max = EFX_MASK32(FSF_AZ_TX_KER_BYTE_COUNT);
141311765Sarybchik	/* Fragments must not span 4k boundaries. */
142311765Sarybchik	encp->enc_tx_dma_desc_boundary = 4096;
143311765Sarybchik
144283514Sarybchik	/* Resource limits */
145283514Sarybchik	rc = efx_mcdi_get_resource_limits(enp, &nevq, &nrxq, &ntxq);
146283514Sarybchik	if (rc != 0) {
147283514Sarybchik		if (rc != ENOTSUP)
148283514Sarybchik			goto fail2;
149283514Sarybchik
150283514Sarybchik		nevq = 1024;
151283514Sarybchik		nrxq = EFX_RXQ_LIMIT_TARGET;
152283514Sarybchik		ntxq = EFX_TXQ_LIMIT_TARGET;
153227569Sphilip	}
154283514Sarybchik	encp->enc_evq_limit = nevq;
155283514Sarybchik	encp->enc_rxq_limit = MIN(EFX_RXQ_LIMIT_TARGET, nrxq);
156283514Sarybchik	encp->enc_txq_limit = MIN(EFX_TXQ_LIMIT_TARGET, ntxq);
157227569Sphilip
158342407Sarybchik	encp->enc_txq_max_ndescs = 4096;
159342407Sarybchik
160227569Sphilip	encp->enc_buftbl_limit = SIENA_SRAM_ROWS -
161279098Sarybchik	    (encp->enc_txq_limit * EFX_TXQ_DC_NDESCS(EFX_TXQ_DC_SIZE)) -
162279098Sarybchik	    (encp->enc_rxq_limit * EFX_RXQ_DC_NDESCS(EFX_RXQ_DC_SIZE));
163227569Sphilip
164283514Sarybchik	encp->enc_hw_tx_insert_vlan_enabled = B_FALSE;
165283514Sarybchik	encp->enc_fw_assisted_tso_enabled = B_FALSE;
166293891Sarybchik	encp->enc_fw_assisted_tso_v2_enabled = B_FALSE;
167311015Sarybchik	encp->enc_fw_assisted_tso_v2_n_contexts = 0;
168291922Sarybchik	encp->enc_allow_set_mac_with_installed_filters = B_TRUE;
169283514Sarybchik
170299904Sarybchik	/* Siena supports two 10G ports, and 8 lanes of PCIe Gen2 */
171299904Sarybchik	encp->enc_required_pcie_bandwidth_mbps = 2 * 10000;
172299904Sarybchik	encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN2;
173299904Sarybchik
174311481Sarybchik	encp->enc_fw_verified_nvram_update_required = B_FALSE;
175311481Sarybchik
176227569Sphilip	return (0);
177227569Sphilip
178227569Sphilipfail2:
179227569Sphilip	EFSYS_PROBE(fail2);
180227569Sphilipfail1:
181291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
182227569Sphilip
183227569Sphilip	return (rc);
184227569Sphilip}
185227569Sphilip
186291436Sarybchikstatic	__checkReturn	efx_rc_t
187227569Sphilipsiena_phy_cfg(
188227569Sphilip	__in		efx_nic_t *enp)
189227569Sphilip{
190342424Sarybchik#if EFSYS_OPT_PHY_STATS
191227569Sphilip	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
192342424Sarybchik#endif	/* EFSYS_OPT_PHY_STATS */
193291436Sarybchik	efx_rc_t rc;
194227569Sphilip
195283514Sarybchik	/* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */
196283514Sarybchik	if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0)
197227569Sphilip		goto fail1;
198227569Sphilip
199227569Sphilip#if EFSYS_OPT_PHY_STATS
200227569Sphilip	/* Convert the MCDI statistic mask into the EFX_PHY_STAT mask */
201283514Sarybchik	siena_phy_decode_stats(enp, encp->enc_mcdi_phy_stat_mask,
202227569Sphilip			    NULL, &encp->enc_phy_stat_mask, NULL);
203227569Sphilip#endif	/* EFSYS_OPT_PHY_STATS */
204227569Sphilip
205227569Sphilip	return (0);
206227569Sphilip
207227569Sphilipfail1:
208291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
209227569Sphilip
210227569Sphilip	return (rc);
211227569Sphilip}
212227569Sphilip
213342436Sarybchik#define	SIENA_BIU_MAGIC0	0x01234567
214342436Sarybchik#define	SIENA_BIU_MAGIC1	0xfedcba98
215342436Sarybchik
216342436Sarybchikstatic	__checkReturn	efx_rc_t
217342436Sarybchiksiena_nic_biu_test(
218342436Sarybchik	__in		efx_nic_t *enp)
219342436Sarybchik{
220342436Sarybchik	efx_oword_t oword;
221342436Sarybchik	efx_rc_t rc;
222342436Sarybchik
223342436Sarybchik	/*
224342436Sarybchik	 * Write magic values to scratch registers 0 and 1, then
225342436Sarybchik	 * verify that the values were written correctly.  Interleave
226342436Sarybchik	 * the accesses to ensure that the BIU is not just reading
227342436Sarybchik	 * back the cached value that was last written.
228342436Sarybchik	 */
229342436Sarybchik	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC0);
230342436Sarybchik	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
231342436Sarybchik
232342436Sarybchik	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC1);
233342436Sarybchik	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
234342436Sarybchik
235342436Sarybchik	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
236342436Sarybchik	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC0) {
237342436Sarybchik		rc = EIO;
238342436Sarybchik		goto fail1;
239342436Sarybchik	}
240342436Sarybchik
241342436Sarybchik	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
242342436Sarybchik	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC1) {
243342436Sarybchik		rc = EIO;
244342436Sarybchik		goto fail2;
245342436Sarybchik	}
246342436Sarybchik
247342436Sarybchik	/*
248342436Sarybchik	 * Perform the same test, with the values swapped.  This
249342436Sarybchik	 * ensures that subsequent tests don't start with the correct
250342436Sarybchik	 * values already written into the scratch registers.
251342436Sarybchik	 */
252342436Sarybchik	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC1);
253342436Sarybchik	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
254342436Sarybchik
255342436Sarybchik	EFX_POPULATE_OWORD_1(oword, FRF_AZ_DRIVER_DW0, SIENA_BIU_MAGIC0);
256342436Sarybchik	EFX_BAR_TBL_WRITEO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
257342436Sarybchik
258342436Sarybchik	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 0, &oword, B_TRUE);
259342436Sarybchik	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC1) {
260342436Sarybchik		rc = EIO;
261342436Sarybchik		goto fail3;
262342436Sarybchik	}
263342436Sarybchik
264342436Sarybchik	EFX_BAR_TBL_READO(enp, FR_AZ_DRIVER_REG, 1, &oword, B_TRUE);
265342436Sarybchik	if (EFX_OWORD_FIELD(oword, FRF_AZ_DRIVER_DW0) != SIENA_BIU_MAGIC0) {
266342436Sarybchik		rc = EIO;
267342436Sarybchik		goto fail4;
268342436Sarybchik	}
269342436Sarybchik
270342436Sarybchik	return (0);
271342436Sarybchik
272342436Sarybchikfail4:
273342436Sarybchik	EFSYS_PROBE(fail4);
274342436Sarybchikfail3:
275342436Sarybchik	EFSYS_PROBE(fail3);
276342436Sarybchikfail2:
277342436Sarybchik	EFSYS_PROBE(fail2);
278342436Sarybchikfail1:
279342436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
280342436Sarybchik
281342436Sarybchik	return (rc);
282342436Sarybchik}
283342436Sarybchik
284291436Sarybchik	__checkReturn	efx_rc_t
285227569Sphilipsiena_nic_probe(
286227569Sphilip	__in		efx_nic_t *enp)
287227569Sphilip{
288227569Sphilip	efx_port_t *epp = &(enp->en_port);
289227569Sphilip	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
290227569Sphilip	siena_link_state_t sls;
291227569Sphilip	unsigned int mask;
292283514Sarybchik	efx_oword_t oword;
293291436Sarybchik	efx_rc_t rc;
294227569Sphilip
295227569Sphilip	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
296227569Sphilip
297283514Sarybchik	/* Test BIU */
298342436Sarybchik	if ((rc = siena_nic_biu_test(enp)) != 0)
299227569Sphilip		goto fail1;
300227569Sphilip
301283514Sarybchik	/* Clear the region register */
302283514Sarybchik	EFX_POPULATE_OWORD_4(oword,
303283514Sarybchik	    FRF_AZ_ADR_REGION0, 0,
304283514Sarybchik	    FRF_AZ_ADR_REGION1, (1 << 16),
305283514Sarybchik	    FRF_AZ_ADR_REGION2, (2 << 16),
306283514Sarybchik	    FRF_AZ_ADR_REGION3, (3 << 16));
307283514Sarybchik	EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword);
308283514Sarybchik
309283514Sarybchik	/* Read clear any assertion state */
310283514Sarybchik	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
311227569Sphilip		goto fail2;
312227569Sphilip
313283514Sarybchik	/* Exit the assertion handler */
314283514Sarybchik	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
315227569Sphilip		goto fail3;
316227569Sphilip
317283514Sarybchik	/* Wrestle control from the BMC */
318283514Sarybchik	if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0)
319227569Sphilip		goto fail4;
320227569Sphilip
321283514Sarybchik	if ((rc = siena_board_cfg(enp)) != 0)
322227569Sphilip		goto fail5;
323227569Sphilip
324283514Sarybchik	if ((rc = siena_phy_cfg(enp)) != 0)
325283514Sarybchik		goto fail6;
326283514Sarybchik
327227569Sphilip	/* Obtain the default PHY advertised capabilities */
328227569Sphilip	if ((rc = siena_nic_reset(enp)) != 0)
329283514Sarybchik		goto fail7;
330227569Sphilip	if ((rc = siena_phy_get_link(enp, &sls)) != 0)
331283514Sarybchik		goto fail8;
332227569Sphilip	epp->ep_default_adv_cap_mask = sls.sls_adv_cap_mask;
333227569Sphilip	epp->ep_adv_cap_mask = sls.sls_adv_cap_mask;
334227569Sphilip
335227569Sphilip#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
336227569Sphilip	if ((rc = siena_nic_get_partn_mask(enp, &mask)) != 0)
337283514Sarybchik		goto fail9;
338227569Sphilip	enp->en_u.siena.enu_partn_mask = mask;
339227569Sphilip#endif
340227569Sphilip
341227569Sphilip#if EFSYS_OPT_MAC_STATS
342227569Sphilip	/* Wipe the MAC statistics */
343283514Sarybchik	if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0)
344283514Sarybchik		goto fail10;
345227569Sphilip#endif
346227569Sphilip
347227569Sphilip#if EFSYS_OPT_LOOPBACK
348283514Sarybchik	if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0)
349283514Sarybchik		goto fail11;
350227569Sphilip#endif
351227569Sphilip
352227569Sphilip#if EFSYS_OPT_MON_STATS
353283514Sarybchik	if ((rc = mcdi_mon_cfg_build(enp)) != 0)
354283514Sarybchik		goto fail12;
355227569Sphilip#endif
356227569Sphilip
357227569Sphilip	encp->enc_features = enp->en_features;
358227569Sphilip
359227569Sphilip	return (0);
360227569Sphilip
361227569Sphilip#if EFSYS_OPT_MON_STATS
362283514Sarybchikfail12:
363283514Sarybchik	EFSYS_PROBE(fail12);
364283514Sarybchik#endif
365283514Sarybchik#if EFSYS_OPT_LOOPBACK
366227569Sphilipfail11:
367227569Sphilip	EFSYS_PROBE(fail11);
368227569Sphilip#endif
369283514Sarybchik#if EFSYS_OPT_MAC_STATS
370227569Sphilipfail10:
371227569Sphilip	EFSYS_PROBE(fail10);
372227569Sphilip#endif
373283514Sarybchik#if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM
374227569Sphilipfail9:
375227569Sphilip	EFSYS_PROBE(fail9);
376227569Sphilip#endif
377227569Sphilipfail8:
378227569Sphilip	EFSYS_PROBE(fail8);
379227569Sphilipfail7:
380227569Sphilip	EFSYS_PROBE(fail7);
381227569Sphilipfail6:
382227569Sphilip	EFSYS_PROBE(fail6);
383227569Sphilipfail5:
384227569Sphilip	EFSYS_PROBE(fail5);
385227569Sphilipfail4:
386227569Sphilip	EFSYS_PROBE(fail4);
387227569Sphilipfail3:
388227569Sphilip	EFSYS_PROBE(fail3);
389227569Sphilipfail2:
390227569Sphilip	EFSYS_PROBE(fail2);
391227569Sphilipfail1:
392291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
393227569Sphilip
394227569Sphilip	return (rc);
395227569Sphilip}
396227569Sphilip
397291436Sarybchik	__checkReturn	efx_rc_t
398227569Sphilipsiena_nic_reset(
399227569Sphilip	__in		efx_nic_t *enp)
400227569Sphilip{
401227569Sphilip	efx_mcdi_req_t req;
402291436Sarybchik	efx_rc_t rc;
403227569Sphilip
404227569Sphilip	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
405227569Sphilip
406227569Sphilip	/* siena_nic_reset() is called to recover from BADASSERT failures. */
407283514Sarybchik	if ((rc = efx_mcdi_read_assertion(enp)) != 0)
408227569Sphilip		goto fail1;
409283514Sarybchik	if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0)
410227569Sphilip		goto fail2;
411227569Sphilip
412283514Sarybchik	/*
413283514Sarybchik	 * Bug24908: ENTITY_RESET_IN_LEN is non zero but zero may be supplied
414283514Sarybchik	 * for backwards compatibility with PORT_RESET_IN_LEN.
415283514Sarybchik	 */
416283514Sarybchik	EFX_STATIC_ASSERT(MC_CMD_ENTITY_RESET_OUT_LEN == 0);
417283514Sarybchik
418283514Sarybchik	req.emr_cmd = MC_CMD_ENTITY_RESET;
419227569Sphilip	req.emr_in_buf = NULL;
420227569Sphilip	req.emr_in_length = 0;
421227569Sphilip	req.emr_out_buf = NULL;
422227569Sphilip	req.emr_out_length = 0;
423227569Sphilip
424227569Sphilip	efx_mcdi_execute(enp, &req);
425227569Sphilip
426227569Sphilip	if (req.emr_rc != 0) {
427227569Sphilip		rc = req.emr_rc;
428227569Sphilip		goto fail3;
429227569Sphilip	}
430227569Sphilip
431227569Sphilip	return (0);
432227569Sphilip
433227569Sphilipfail3:
434227569Sphilip	EFSYS_PROBE(fail3);
435227569Sphilipfail2:
436227569Sphilip	EFSYS_PROBE(fail2);
437227569Sphilipfail1:
438291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
439227569Sphilip
440227569Sphilip	return (0);
441227569Sphilip}
442227569Sphilip
443227569Sphilipstatic			void
444227569Sphilipsiena_nic_rx_cfg(
445227569Sphilip	__in		efx_nic_t *enp)
446227569Sphilip{
447227569Sphilip	efx_oword_t oword;
448227569Sphilip
449227569Sphilip	/*
450227569Sphilip	 * RX_INGR_EN is always enabled on Siena, because we rely on
451227569Sphilip	 * the RX parser to be resiliant to missing SOP/EOP.
452227569Sphilip	 */
453227569Sphilip	EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
454227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_INGR_EN, 1);
455227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
456227569Sphilip
457227569Sphilip	/* Disable parsing of additional 802.1Q in Q packets */
458227569Sphilip	EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
459227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES, 0);
460227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
461227569Sphilip}
462227569Sphilip
463227569Sphilipstatic			void
464227569Sphilipsiena_nic_usrev_dis(
465227569Sphilip	__in		efx_nic_t *enp)
466227569Sphilip{
467227569Sphilip	efx_oword_t	oword;
468227569Sphilip
469227569Sphilip	EFX_POPULATE_OWORD_1(oword, FRF_CZ_USREV_DIS, 1);
470227569Sphilip	EFX_BAR_WRITEO(enp, FR_CZ_USR_EV_CFG, &oword);
471227569Sphilip}
472227569Sphilip
473291436Sarybchik	__checkReturn	efx_rc_t
474227569Sphilipsiena_nic_init(
475227569Sphilip	__in		efx_nic_t *enp)
476227569Sphilip{
477291436Sarybchik	efx_rc_t rc;
478227569Sphilip
479227569Sphilip	EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA);
480227569Sphilip
481283514Sarybchik	/* Enable reporting of some events (e.g. link change) */
482283514Sarybchik	if ((rc = efx_mcdi_log_ctrl(enp)) != 0)
483227569Sphilip		goto fail1;
484227569Sphilip
485227569Sphilip	siena_sram_init(enp);
486227569Sphilip
487227569Sphilip	/* Configure Siena's RX block */
488227569Sphilip	siena_nic_rx_cfg(enp);
489227569Sphilip
490227569Sphilip	/* Disable USR_EVents for now */
491227569Sphilip	siena_nic_usrev_dis(enp);
492227569Sphilip
493227569Sphilip	/* bug17057: Ensure set_link is called */
494227569Sphilip	if ((rc = siena_phy_reconfigure(enp)) != 0)
495227569Sphilip		goto fail2;
496227569Sphilip
497291923Sarybchik	enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V1;
498291923Sarybchik
499227569Sphilip	return (0);
500227569Sphilip
501227569Sphilipfail2:
502227569Sphilip	EFSYS_PROBE(fail2);
503227569Sphilipfail1:
504291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
505227569Sphilip
506227569Sphilip	return (rc);
507227569Sphilip}
508227569Sphilip
509227569Sphilip			void
510227569Sphilipsiena_nic_fini(
511227569Sphilip	__in		efx_nic_t *enp)
512227569Sphilip{
513227569Sphilip	_NOTE(ARGUNUSED(enp))
514227569Sphilip}
515227569Sphilip
516227569Sphilip			void
517227569Sphilipsiena_nic_unprobe(
518227569Sphilip	__in		efx_nic_t *enp)
519227569Sphilip{
520283514Sarybchik#if EFSYS_OPT_MON_STATS
521283514Sarybchik	mcdi_mon_cfg_free(enp);
522283514Sarybchik#endif /* EFSYS_OPT_MON_STATS */
523283514Sarybchik	(void) efx_mcdi_drv_attach(enp, B_FALSE);
524227569Sphilip}
525227569Sphilip
526227569Sphilip#if EFSYS_OPT_DIAG
527227569Sphilip
528342425Sarybchikstatic siena_register_set_t __siena_registers[] = {
529227569Sphilip	{ FR_AZ_ADR_REGION_REG_OFST, 0, 1 },
530227569Sphilip	{ FR_CZ_USR_EV_CFG_OFST, 0, 1 },
531227569Sphilip	{ FR_AZ_RX_CFG_REG_OFST, 0, 1 },
532227569Sphilip	{ FR_AZ_TX_CFG_REG_OFST, 0, 1 },
533227569Sphilip	{ FR_AZ_TX_RESERVED_REG_OFST, 0, 1 },
534227569Sphilip	{ FR_AZ_SRM_TX_DC_CFG_REG_OFST, 0, 1 },
535227569Sphilip	{ FR_AZ_RX_DC_CFG_REG_OFST, 0, 1 },
536227569Sphilip	{ FR_AZ_RX_DC_PF_WM_REG_OFST, 0, 1 },
537227569Sphilip	{ FR_AZ_DP_CTRL_REG_OFST, 0, 1 },
538227569Sphilip	{ FR_BZ_RX_RSS_TKEY_REG_OFST, 0, 1},
539227569Sphilip	{ FR_CZ_RX_RSS_IPV6_REG1_OFST, 0, 1},
540227569Sphilip	{ FR_CZ_RX_RSS_IPV6_REG2_OFST, 0, 1},
541227569Sphilip	{ FR_CZ_RX_RSS_IPV6_REG3_OFST, 0, 1}
542227569Sphilip};
543227569Sphilip
544283514Sarybchikstatic const uint32_t __siena_register_masks[] = {
545227569Sphilip	0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF,
546227569Sphilip	0x000103FF, 0x00000000, 0x00000000, 0x00000000,
547227569Sphilip	0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000,
548227569Sphilip	0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF,
549227569Sphilip	0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF,
550227569Sphilip	0x001FFFFF, 0x00000000, 0x00000000, 0x00000000,
551227569Sphilip	0x00000003, 0x00000000, 0x00000000, 0x00000000,
552227569Sphilip	0x000003FF, 0x00000000, 0x00000000, 0x00000000,
553227569Sphilip	0x00000FFF, 0x00000000, 0x00000000, 0x00000000,
554227569Sphilip	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
555227569Sphilip	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
556227569Sphilip	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
557227569Sphilip	0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000
558227569Sphilip};
559227569Sphilip
560342425Sarybchikstatic siena_register_set_t __siena_tables[] = {
561227569Sphilip	{ FR_AZ_RX_FILTER_TBL0_OFST, FR_AZ_RX_FILTER_TBL0_STEP,
562227569Sphilip	    FR_AZ_RX_FILTER_TBL0_ROWS },
563227569Sphilip	{ FR_CZ_RX_MAC_FILTER_TBL0_OFST, FR_CZ_RX_MAC_FILTER_TBL0_STEP,
564227569Sphilip	    FR_CZ_RX_MAC_FILTER_TBL0_ROWS },
565227569Sphilip	{ FR_AZ_RX_DESC_PTR_TBL_OFST,
566227569Sphilip	    FR_AZ_RX_DESC_PTR_TBL_STEP, FR_CZ_RX_DESC_PTR_TBL_ROWS },
567227569Sphilip	{ FR_AZ_TX_DESC_PTR_TBL_OFST,
568227569Sphilip	    FR_AZ_TX_DESC_PTR_TBL_STEP, FR_CZ_TX_DESC_PTR_TBL_ROWS },
569227569Sphilip	{ FR_AZ_TIMER_TBL_OFST, FR_AZ_TIMER_TBL_STEP, FR_CZ_TIMER_TBL_ROWS },
570227569Sphilip	{ FR_CZ_TX_FILTER_TBL0_OFST,
571227569Sphilip	    FR_CZ_TX_FILTER_TBL0_STEP, FR_CZ_TX_FILTER_TBL0_ROWS },
572227569Sphilip	{ FR_CZ_TX_MAC_FILTER_TBL0_OFST,
573227569Sphilip	    FR_CZ_TX_MAC_FILTER_TBL0_STEP, FR_CZ_TX_MAC_FILTER_TBL0_ROWS }
574227569Sphilip};
575227569Sphilip
576283514Sarybchikstatic const uint32_t __siena_table_masks[] = {
577227569Sphilip	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF,
578227569Sphilip	0xFFFF0FFF, 0xFFFFFFFF, 0x00000E7F, 0x00000000,
579279095Sarybchik	0xFFFFFFFE, 0x0FFFFFFF, 0x01800000, 0x00000000,
580227569Sphilip	0xFFFFFFFE, 0x0FFFFFFF, 0x0C000000, 0x00000000,
581227569Sphilip	0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
582227569Sphilip	0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000013FF,
583227569Sphilip	0xFFFF07FF, 0xFFFFFFFF, 0x0000007F, 0x00000000,
584227569Sphilip};
585227569Sphilip
586291436Sarybchik	__checkReturn	efx_rc_t
587342425Sarybchiksiena_nic_test_registers(
588342425Sarybchik	__in		efx_nic_t *enp,
589342425Sarybchik	__in		siena_register_set_t *rsp,
590342425Sarybchik	__in		size_t count)
591342425Sarybchik{
592342425Sarybchik	unsigned int bit;
593342425Sarybchik	efx_oword_t original;
594342425Sarybchik	efx_oword_t reg;
595342425Sarybchik	efx_oword_t buf;
596342425Sarybchik	efx_rc_t rc;
597342425Sarybchik
598342425Sarybchik	while (count > 0) {
599342425Sarybchik		/* This function is only suitable for registers */
600342425Sarybchik		EFSYS_ASSERT(rsp->rows == 1);
601342425Sarybchik
602342425Sarybchik		/* bit sweep on and off */
603342425Sarybchik		EFSYS_BAR_READO(enp->en_esbp, rsp->address, &original,
604342425Sarybchik			    B_TRUE);
605342425Sarybchik		for (bit = 0; bit < 128; bit++) {
606342425Sarybchik			/* Is this bit in the mask? */
607342425Sarybchik			if (~(rsp->mask.eo_u32[bit >> 5]) & (1 << bit))
608342425Sarybchik				continue;
609342425Sarybchik
610342425Sarybchik			/* Test this bit can be set in isolation */
611342425Sarybchik			reg = original;
612342425Sarybchik			EFX_AND_OWORD(reg, rsp->mask);
613342425Sarybchik			EFX_SET_OWORD_BIT(reg, bit);
614342425Sarybchik
615342425Sarybchik			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
616342425Sarybchik				    B_TRUE);
617342425Sarybchik			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
618342425Sarybchik				    B_TRUE);
619342425Sarybchik
620342425Sarybchik			EFX_AND_OWORD(buf, rsp->mask);
621342425Sarybchik			if (memcmp(&reg, &buf, sizeof (reg))) {
622342425Sarybchik				rc = EIO;
623342425Sarybchik				goto fail1;
624342425Sarybchik			}
625342425Sarybchik
626342425Sarybchik			/* Test this bit can be cleared in isolation */
627342425Sarybchik			EFX_OR_OWORD(reg, rsp->mask);
628342425Sarybchik			EFX_CLEAR_OWORD_BIT(reg, bit);
629342425Sarybchik
630342425Sarybchik			EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &reg,
631342425Sarybchik				    B_TRUE);
632342425Sarybchik			EFSYS_BAR_READO(enp->en_esbp, rsp->address, &buf,
633342425Sarybchik				    B_TRUE);
634342425Sarybchik
635342425Sarybchik			EFX_AND_OWORD(buf, rsp->mask);
636342425Sarybchik			if (memcmp(&reg, &buf, sizeof (reg))) {
637342425Sarybchik				rc = EIO;
638342425Sarybchik				goto fail2;
639342425Sarybchik			}
640342425Sarybchik		}
641342425Sarybchik
642342425Sarybchik		/* Restore the old value */
643342425Sarybchik		EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original,
644342425Sarybchik			    B_TRUE);
645342425Sarybchik
646342425Sarybchik		--count;
647342425Sarybchik		++rsp;
648342425Sarybchik	}
649342425Sarybchik
650342425Sarybchik	return (0);
651342425Sarybchik
652342425Sarybchikfail2:
653342425Sarybchik	EFSYS_PROBE(fail2);
654342425Sarybchikfail1:
655342425Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
656342425Sarybchik
657342425Sarybchik	/* Restore the old value */
658342425Sarybchik	EFSYS_BAR_WRITEO(enp->en_esbp, rsp->address, &original, B_TRUE);
659342425Sarybchik
660342425Sarybchik	return (rc);
661342425Sarybchik}
662342425Sarybchik
663342425Sarybchik	__checkReturn	efx_rc_t
664342425Sarybchiksiena_nic_test_tables(
665342425Sarybchik	__in		efx_nic_t *enp,
666342425Sarybchik	__in		siena_register_set_t *rsp,
667342425Sarybchik	__in		efx_pattern_type_t pattern,
668342425Sarybchik	__in		size_t count)
669342425Sarybchik{
670342425Sarybchik	efx_sram_pattern_fn_t func;
671342425Sarybchik	unsigned int index;
672342425Sarybchik	unsigned int address;
673342425Sarybchik	efx_oword_t reg;
674342425Sarybchik	efx_oword_t buf;
675342425Sarybchik	efx_rc_t rc;
676342425Sarybchik
677342425Sarybchik	EFSYS_ASSERT(pattern < EFX_PATTERN_NTYPES);
678342425Sarybchik	func = __efx_sram_pattern_fns[pattern];
679342425Sarybchik
680342425Sarybchik	while (count > 0) {
681342425Sarybchik		/* Write */
682342425Sarybchik		address = rsp->address;
683342425Sarybchik		for (index = 0; index < rsp->rows; ++index) {
684342425Sarybchik			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
685342425Sarybchik			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
686342425Sarybchik			EFX_AND_OWORD(reg, rsp->mask);
687342425Sarybchik			EFSYS_BAR_WRITEO(enp->en_esbp, address, &reg, B_TRUE);
688342425Sarybchik
689342425Sarybchik			address += rsp->step;
690342425Sarybchik		}
691342425Sarybchik
692342425Sarybchik		/* Read */
693342425Sarybchik		address = rsp->address;
694342425Sarybchik		for (index = 0; index < rsp->rows; ++index) {
695342425Sarybchik			func(2 * index + 0, B_FALSE, &reg.eo_qword[0]);
696342425Sarybchik			func(2 * index + 1, B_FALSE, &reg.eo_qword[1]);
697342425Sarybchik			EFX_AND_OWORD(reg, rsp->mask);
698342425Sarybchik			EFSYS_BAR_READO(enp->en_esbp, address, &buf, B_TRUE);
699342425Sarybchik			if (memcmp(&reg, &buf, sizeof (reg))) {
700342425Sarybchik				rc = EIO;
701342425Sarybchik				goto fail1;
702342425Sarybchik			}
703342425Sarybchik
704342425Sarybchik			address += rsp->step;
705342425Sarybchik		}
706342425Sarybchik
707342425Sarybchik		++rsp;
708342425Sarybchik		--count;
709342425Sarybchik	}
710342425Sarybchik
711342425Sarybchik	return (0);
712342425Sarybchik
713342425Sarybchikfail1:
714342425Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
715342425Sarybchik
716342425Sarybchik	return (rc);
717342425Sarybchik}
718342425Sarybchik
719342425Sarybchik
720342425Sarybchik	__checkReturn	efx_rc_t
721227569Sphilipsiena_nic_register_test(
722227569Sphilip	__in		efx_nic_t *enp)
723227569Sphilip{
724342425Sarybchik	siena_register_set_t *rsp;
725227569Sphilip	const uint32_t *dwordp;
726227569Sphilip	unsigned int nitems;
727227569Sphilip	unsigned int count;
728291436Sarybchik	efx_rc_t rc;
729227569Sphilip
730227569Sphilip	/* Fill out the register mask entries */
731227569Sphilip	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_register_masks)
732227569Sphilip		    == EFX_ARRAY_SIZE(__siena_registers) * 4);
733227569Sphilip
734227569Sphilip	nitems = EFX_ARRAY_SIZE(__siena_registers);
735227569Sphilip	dwordp = __siena_register_masks;
736227569Sphilip	for (count = 0; count < nitems; ++count) {
737227569Sphilip		rsp = __siena_registers + count;
738227569Sphilip		rsp->mask.eo_u32[0] = *dwordp++;
739227569Sphilip		rsp->mask.eo_u32[1] = *dwordp++;
740227569Sphilip		rsp->mask.eo_u32[2] = *dwordp++;
741227569Sphilip		rsp->mask.eo_u32[3] = *dwordp++;
742227569Sphilip	}
743227569Sphilip
744227569Sphilip	/* Fill out the register table entries */
745227569Sphilip	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_table_masks)
746227569Sphilip		    == EFX_ARRAY_SIZE(__siena_tables) * 4);
747227569Sphilip
748227569Sphilip	nitems = EFX_ARRAY_SIZE(__siena_tables);
749227569Sphilip	dwordp = __siena_table_masks;
750227569Sphilip	for (count = 0; count < nitems; ++count) {
751227569Sphilip		rsp = __siena_tables + count;
752227569Sphilip		rsp->mask.eo_u32[0] = *dwordp++;
753227569Sphilip		rsp->mask.eo_u32[1] = *dwordp++;
754227569Sphilip		rsp->mask.eo_u32[2] = *dwordp++;
755227569Sphilip		rsp->mask.eo_u32[3] = *dwordp++;
756227569Sphilip	}
757227569Sphilip
758342425Sarybchik	if ((rc = siena_nic_test_registers(enp, __siena_registers,
759227569Sphilip	    EFX_ARRAY_SIZE(__siena_registers))) != 0)
760227569Sphilip		goto fail1;
761227569Sphilip
762342425Sarybchik	if ((rc = siena_nic_test_tables(enp, __siena_tables,
763227569Sphilip	    EFX_PATTERN_BYTE_ALTERNATE,
764227569Sphilip	    EFX_ARRAY_SIZE(__siena_tables))) != 0)
765227569Sphilip		goto fail2;
766227569Sphilip
767342425Sarybchik	if ((rc = siena_nic_test_tables(enp, __siena_tables,
768227569Sphilip	    EFX_PATTERN_BYTE_CHANGING,
769227569Sphilip	    EFX_ARRAY_SIZE(__siena_tables))) != 0)
770227569Sphilip		goto fail3;
771227569Sphilip
772342425Sarybchik	if ((rc = siena_nic_test_tables(enp, __siena_tables,
773227569Sphilip	    EFX_PATTERN_BIT_SWEEP, EFX_ARRAY_SIZE(__siena_tables))) != 0)
774227569Sphilip		goto fail4;
775227569Sphilip
776227569Sphilip	return (0);
777227569Sphilip
778227569Sphilipfail4:
779227569Sphilip	EFSYS_PROBE(fail4);
780227569Sphilipfail3:
781227569Sphilip	EFSYS_PROBE(fail3);
782227569Sphilipfail2:
783227569Sphilip	EFSYS_PROBE(fail2);
784227569Sphilipfail1:
785291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
786227569Sphilip
787227569Sphilip	return (rc);
788227569Sphilip}
789227569Sphilip
790227569Sphilip#endif	/* EFSYS_OPT_DIAG */
791227569Sphilip
792227569Sphilip#endif	/* EFSYS_OPT_SIENA */
793