1ebb7c6fdSAlex Wilson /*
2ebb7c6fdSAlex Wilson  * This file and its contents are supplied under the terms of the
3ebb7c6fdSAlex Wilson  * Common Development and Distribution License ("CDDL"), version 1.0.
4ebb7c6fdSAlex Wilson  * You may only use this file in accordance with the terms of version
5ebb7c6fdSAlex Wilson  * 1.0 of the CDDL.
6ebb7c6fdSAlex Wilson  *
7ebb7c6fdSAlex Wilson  * A full copy of the text of the CDDL should have accompanied this
8ebb7c6fdSAlex Wilson  * source.  A copy of the CDDL is also available via the Internet at
9ebb7c6fdSAlex Wilson  * http://www.illumos.org/license/CDDL.
10ebb7c6fdSAlex Wilson  */
11ebb7c6fdSAlex Wilson 
12ebb7c6fdSAlex Wilson /*
1380d1a7bdSAlex Wilson  * Copyright (c) 2021, the University of Queensland
148b11ca88SPaul Winder  * Copyright 2020 RackTop Systems, Inc.
15*85e4aa97SDan McDonald  * Copyright 2023 MNX Cloud, Inc.
16ebb7c6fdSAlex Wilson  */
17ebb7c6fdSAlex Wilson 
18ebb7c6fdSAlex Wilson /*
19ebb7c6fdSAlex Wilson  * Mellanox Connect-X 4/5/6 driver.
20ebb7c6fdSAlex Wilson  */
21ebb7c6fdSAlex Wilson 
22ebb7c6fdSAlex Wilson #include <sys/modctl.h>
23ebb7c6fdSAlex Wilson #include <sys/conf.h>
24ebb7c6fdSAlex Wilson #include <sys/devops.h>
25ebb7c6fdSAlex Wilson #include <sys/sysmacros.h>
26ebb7c6fdSAlex Wilson #include <sys/vlan.h>
27ebb7c6fdSAlex Wilson 
28ebb7c6fdSAlex Wilson #include <sys/pattr.h>
29ebb7c6fdSAlex Wilson #include <sys/dlpi.h>
30ebb7c6fdSAlex Wilson 
31ebb7c6fdSAlex Wilson #include <sys/mac_provider.h>
32ebb7c6fdSAlex Wilson 
33ebb7c6fdSAlex Wilson /* Need these for mac_vlan_header_info() */
34ebb7c6fdSAlex Wilson #include <sys/mac_client.h>
35ebb7c6fdSAlex Wilson #include <sys/mac_client_priv.h>
36ebb7c6fdSAlex Wilson 
37ebb7c6fdSAlex Wilson #include <mlxcx.h>
38ebb7c6fdSAlex Wilson 
39ebb7c6fdSAlex Wilson static char *mlxcx_priv_props[] = {
40ebb7c6fdSAlex Wilson 	NULL
41ebb7c6fdSAlex Wilson };
42ebb7c6fdSAlex Wilson 
43ebb7c6fdSAlex Wilson #define	MBITS		1000000ULL
44ebb7c6fdSAlex Wilson #define	GBITS		(1000ULL * MBITS)
45ebb7c6fdSAlex Wilson 
46ebb7c6fdSAlex Wilson static uint64_t
mlxcx_speed_to_bits(mlxcx_eth_proto_t proto,mlxcx_ext_eth_proto_t ext_proto)47*85e4aa97SDan McDonald mlxcx_speed_to_bits(mlxcx_eth_proto_t proto, mlxcx_ext_eth_proto_t ext_proto)
48ebb7c6fdSAlex Wilson {
49*85e4aa97SDan McDonald 	/*
50*85e4aa97SDan McDonald 	 * Older parts only used "proto", but starting with ConnectX-6, there
51*85e4aa97SDan McDonald 	 * might be speeds & link-types in an extended set of proto bits.
52*85e4aa97SDan McDonald 	 *
53*85e4aa97SDan McDonald 	 * We check the old bits first because the extended bits do not report
54*85e4aa97SDan McDonald 	 * media on links (e.g. nothing like MLXCX_EXTPROTO_100GBASE_CR2
55*85e4aa97SDan McDonald 	 * for a 50Gbit lane).
56*85e4aa97SDan McDonald 	 *
57*85e4aa97SDan McDonald 	 * In the case of, e.g., 100GBASE_CR4 both proto and ext_proto have
58*85e4aa97SDan McDonald 	 * bits set, but the extended proto bits are a generic CAUI4 indicator
59*85e4aa97SDan McDonald 	 * that could be for CR4, KR4, etc. If we get a legitimate single-bit
60*85e4aa97SDan McDonald 	 * value, we don't worry about ext_proto. This may change in the face
61*85e4aa97SDan McDonald 	 * of other HW or cabling, however.
62*85e4aa97SDan McDonald 	 */
63*85e4aa97SDan McDonald 	switch (proto) {
64*85e4aa97SDan McDonald 	case MLXCX_PROTO_NONE:	/* Aka "0" */
65*85e4aa97SDan McDonald 		/* Go straight to checking ext_proto. */
66*85e4aa97SDan McDonald 		break;
67ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_SGMII_100BASE:
68*85e4aa97SDan McDonald 	case MLXCX_PROTO_100BASE_TX:
69ebb7c6fdSAlex Wilson 		return (100ULL * MBITS);
70ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_SGMII:
71ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_1000BASE_KX:
72*85e4aa97SDan McDonald 	case MLXCX_PROTO_1000BASE_T:
73ebb7c6fdSAlex Wilson 		return (1000ULL * MBITS);
74ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_10GBASE_CX4:
75ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_10GBASE_KX4:
76ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_10GBASE_KR:
77ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_10GBASE_CR:
78ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_10GBASE_SR:
79ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_10GBASE_ER_LR:
80*85e4aa97SDan McDonald 	case MLXCX_PROTO_10GBASE_T:
81ebb7c6fdSAlex Wilson 		return (10ULL * GBITS);
82ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_40GBASE_CR4:
83ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_40GBASE_KR4:
84ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_40GBASE_SR4:
85ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_40GBASE_LR4_ER4:
86ebb7c6fdSAlex Wilson 		return (40ULL * GBITS);
87ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_25GBASE_CR:
88ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_25GBASE_KR:
89ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_25GBASE_SR:
90ebb7c6fdSAlex Wilson 		return (25ULL * GBITS);
91ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_50GBASE_SR2:
92ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_50GBASE_CR2:
93ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_50GBASE_KR2:
94ebb7c6fdSAlex Wilson 		return (50ULL * GBITS);
95ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_100GBASE_CR4:
96ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_100GBASE_SR4:
97ebb7c6fdSAlex Wilson 	case MLXCX_PROTO_100GBASE_KR4:
98*85e4aa97SDan McDonald 	case MLXCX_PROTO_100GBASE_LR4_ER4:
99ebb7c6fdSAlex Wilson 		return (100ULL * GBITS);
100ebb7c6fdSAlex Wilson 	default:
101*85e4aa97SDan McDonald 		/*
102*85e4aa97SDan McDonald 		 * We've checked for 0 explicitly above, so don't worry here.
103*85e4aa97SDan McDonald 		 *
104*85e4aa97SDan McDonald 		 * There ARE legitimate single-bit values we don't support,
105*85e4aa97SDan McDonald 		 * and should just return 0 immediately.  We will ASSERT()
106*85e4aa97SDan McDonald 		 * that it's a single-bit value, however, since the passed-in
107*85e4aa97SDan McDonald 		 * values are from the "operational" register, which is only
108*85e4aa97SDan McDonald 		 * supposed to have one bit set. If the assertion fails
109*85e4aa97SDan McDonald 		 * there's either a hardware error or a severe
110*85e4aa97SDan McDonald 		 * misunderstanding of the register.
111*85e4aa97SDan McDonald 		 */
112*85e4aa97SDan McDonald 		ASSERT0((uint32_t)proto & ((uint32_t)proto - 1U));
113ebb7c6fdSAlex Wilson 		return (0);
114ebb7c6fdSAlex Wilson 	}
115*85e4aa97SDan McDonald 
116*85e4aa97SDan McDonald 	switch (ext_proto) {
117*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_SGMII_100BASE:
118*85e4aa97SDan McDonald 		return (100ULL * MBITS);
119*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_1000BASE_X_SGMII:
120*85e4aa97SDan McDonald 		return (1000ULL * MBITS);
121*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_5GBASE_R:
122*85e4aa97SDan McDonald 		return (5ULL * GBITS);
123*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_10GBASE_XFI_XAUI_1:
124*85e4aa97SDan McDonald 		return (10ULL * GBITS);
125*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_40GBASE_XLAUI_4_XLPPI_4:
126*85e4aa97SDan McDonald 		return (40ULL * GBITS);
127*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_25GAUI_1_25GBASE_CR_KR:
128*85e4aa97SDan McDonald 		return (25ULL * GBITS);
129*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_50GAUI_2_LAUI_2_50GBASE_CR2_KR2:
130*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_50GAUI_1_LAUI_1_50GBASE_CR_KR:
131*85e4aa97SDan McDonald 		return (50ULL * GBITS);
132*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_CAUI_4_100GBASE_CR4_KR4:
133*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_100GAUI_2_100GBASE_CR2_KR2:
134*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_100GAUI_1_100GBASE_CR_KR:
135*85e4aa97SDan McDonald 		return (100ULL * GBITS);
136*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_200GAUI_4_200GBASE_CR4_KR4:
137*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_200GAUI_2_200GBASE_CR2_KR2:
138*85e4aa97SDan McDonald 		return (200ULL * GBITS);
139*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_400GAUI_8_400GBASE_CR8:
140*85e4aa97SDan McDonald 	case MLXCX_EXTPROTO_400GAUI_4_400GBASE_CR4:
141*85e4aa97SDan McDonald 		return (400ULL * GBITS);
142*85e4aa97SDan McDonald 	default:
143*85e4aa97SDan McDonald 		/*
144*85e4aa97SDan McDonald 		 * There ARE legitimate single-bit values we don't support,
145*85e4aa97SDan McDonald 		 * and should just return 0 immediately.  We will ASSERT()
146*85e4aa97SDan McDonald 		 * that it's a single-bit value, however, for reasons detailed
147*85e4aa97SDan McDonald 		 * in the prior `default` case.
148*85e4aa97SDan McDonald 		 */
149*85e4aa97SDan McDonald 		ASSERT0((uint32_t)ext_proto & ((uint32_t)ext_proto - 1U));
150*85e4aa97SDan McDonald 		break;
151*85e4aa97SDan McDonald 	}
152*85e4aa97SDan McDonald 
153*85e4aa97SDan McDonald 	return (0);
154ebb7c6fdSAlex Wilson }
155ebb7c6fdSAlex Wilson 
156d77e6e0fSPaul Winder static link_fec_t
mlxcx_fec_to_link_fec(mlxcx_pplm_fec_active_t mlxcx_fec)157d77e6e0fSPaul Winder mlxcx_fec_to_link_fec(mlxcx_pplm_fec_active_t mlxcx_fec)
158d77e6e0fSPaul Winder {
159d77e6e0fSPaul Winder 	if ((mlxcx_fec & MLXCX_PPLM_FEC_ACTIVE_NONE) != 0)
160d77e6e0fSPaul Winder 		return (LINK_FEC_NONE);
161d77e6e0fSPaul Winder 
162d77e6e0fSPaul Winder 	if ((mlxcx_fec & MLXCX_PPLM_FEC_ACTIVE_FIRECODE) != 0)
163d77e6e0fSPaul Winder 		return (LINK_FEC_BASE_R);
164d77e6e0fSPaul Winder 
165d77e6e0fSPaul Winder 	if ((mlxcx_fec & (MLXCX_PPLM_FEC_ACTIVE_RS528 |
166d77e6e0fSPaul Winder 	    MLXCX_PPLM_FEC_ACTIVE_RS271 | MLXCX_PPLM_FEC_ACTIVE_RS544 |
167d77e6e0fSPaul Winder 	    MLXCX_PPLM_FEC_ACTIVE_RS272)) != 0)
168d77e6e0fSPaul Winder 		return (LINK_FEC_RS);
169d77e6e0fSPaul Winder 
170d77e6e0fSPaul Winder 	return (LINK_FEC_NONE);
171d77e6e0fSPaul Winder }
172d77e6e0fSPaul Winder 
173d77e6e0fSPaul Winder static boolean_t
mlxcx_link_fec_cap(link_fec_t fec,mlxcx_pplm_fec_caps_t * pfecp)174d77e6e0fSPaul Winder mlxcx_link_fec_cap(link_fec_t fec, mlxcx_pplm_fec_caps_t *pfecp)
175d77e6e0fSPaul Winder {
176d77e6e0fSPaul Winder 	mlxcx_pplm_fec_caps_t pplm_fec = 0;
177d77e6e0fSPaul Winder 
178d77e6e0fSPaul Winder 	if ((fec & LINK_FEC_AUTO) != 0) {
179d77e6e0fSPaul Winder 		pplm_fec = MLXCX_PPLM_FEC_CAP_AUTO;
180d77e6e0fSPaul Winder 		fec &= ~LINK_FEC_AUTO;
181d77e6e0fSPaul Winder 	} else if ((fec & LINK_FEC_NONE) != 0) {
182d77e6e0fSPaul Winder 		pplm_fec = MLXCX_PPLM_FEC_CAP_NONE;
183d77e6e0fSPaul Winder 		fec &= ~LINK_FEC_NONE;
184d77e6e0fSPaul Winder 	} else if ((fec & LINK_FEC_RS) != 0) {
185d77e6e0fSPaul Winder 		pplm_fec |= MLXCX_PPLM_FEC_CAP_RS;
186d77e6e0fSPaul Winder 		fec &= ~LINK_FEC_RS;
187d77e6e0fSPaul Winder 	} else if ((fec & LINK_FEC_BASE_R) != 0) {
188d77e6e0fSPaul Winder 		pplm_fec |= MLXCX_PPLM_FEC_CAP_FIRECODE;
189d77e6e0fSPaul Winder 		fec &= ~LINK_FEC_BASE_R;
190d77e6e0fSPaul Winder 	}
191d77e6e0fSPaul Winder 
192d77e6e0fSPaul Winder 	/*
193d77e6e0fSPaul Winder 	 * Only one fec option is allowed.
194d77e6e0fSPaul Winder 	 */
195d77e6e0fSPaul Winder 	if (fec != 0)
196d77e6e0fSPaul Winder 		return (B_FALSE);
197d77e6e0fSPaul Winder 
198d77e6e0fSPaul Winder 	*pfecp = pplm_fec;
199d77e6e0fSPaul Winder 
200d77e6e0fSPaul Winder 	return (B_TRUE);
201d77e6e0fSPaul Winder }
202d77e6e0fSPaul Winder 
203ebb7c6fdSAlex Wilson static int
mlxcx_mac_stat_rfc_2863(mlxcx_t * mlxp,mlxcx_port_t * port,uint_t stat,uint64_t * val)204ebb7c6fdSAlex Wilson mlxcx_mac_stat_rfc_2863(mlxcx_t *mlxp, mlxcx_port_t *port, uint_t stat,
205ebb7c6fdSAlex Wilson     uint64_t *val)
206ebb7c6fdSAlex Wilson {
207ebb7c6fdSAlex Wilson 	int ret = 0;
208ebb7c6fdSAlex Wilson 	boolean_t ok;
209ebb7c6fdSAlex Wilson 	mlxcx_register_data_t data;
210ebb7c6fdSAlex Wilson 	mlxcx_ppcnt_rfc_2863_t *st;
211ebb7c6fdSAlex Wilson 
212ebb7c6fdSAlex Wilson 	ASSERT(mutex_owned(&port->mlp_mtx));
213ebb7c6fdSAlex Wilson 
214ebb7c6fdSAlex Wilson 	bzero(&data, sizeof (data));
215ebb7c6fdSAlex Wilson 	data.mlrd_ppcnt.mlrd_ppcnt_local_port = port->mlp_num + 1;
216ebb7c6fdSAlex Wilson 	data.mlrd_ppcnt.mlrd_ppcnt_grp = MLXCX_PPCNT_GRP_RFC_2863;
217ebb7c6fdSAlex Wilson 	data.mlrd_ppcnt.mlrd_ppcnt_clear = MLXCX_PPCNT_NO_CLEAR;
218ebb7c6fdSAlex Wilson 
219ebb7c6fdSAlex Wilson 	ok = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ,
220ebb7c6fdSAlex Wilson 	    MLXCX_REG_PPCNT, &data);
221ebb7c6fdSAlex Wilson 	if (!ok)
222ebb7c6fdSAlex Wilson 		return (EIO);
223ebb7c6fdSAlex Wilson 	st = &data.mlrd_ppcnt.mlrd_ppcnt_rfc_2863;
224ebb7c6fdSAlex Wilson 
225ebb7c6fdSAlex Wilson 	switch (stat) {
226ebb7c6fdSAlex Wilson 	case MAC_STAT_RBYTES:
227ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_in_octets);
228ebb7c6fdSAlex Wilson 		break;
229ebb7c6fdSAlex Wilson 	case MAC_STAT_MULTIRCV:
230ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_in_mcast_pkts);
231ebb7c6fdSAlex Wilson 		break;
232ebb7c6fdSAlex Wilson 	case MAC_STAT_BRDCSTRCV:
233ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_in_bcast_pkts);
234ebb7c6fdSAlex Wilson 		break;
235ebb7c6fdSAlex Wilson 	case MAC_STAT_MULTIXMT:
236ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_out_mcast_pkts);
237ebb7c6fdSAlex Wilson 		break;
238ebb7c6fdSAlex Wilson 	case MAC_STAT_BRDCSTXMT:
239ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_out_bcast_pkts);
240ebb7c6fdSAlex Wilson 		break;
241ebb7c6fdSAlex Wilson 	case MAC_STAT_IERRORS:
242ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_in_errors);
243ebb7c6fdSAlex Wilson 		break;
244ebb7c6fdSAlex Wilson 	case MAC_STAT_UNKNOWNS:
245ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_in_unknown_protos);
246ebb7c6fdSAlex Wilson 		break;
247ebb7c6fdSAlex Wilson 	case MAC_STAT_OERRORS:
248ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_out_errors);
249ebb7c6fdSAlex Wilson 		break;
250ebb7c6fdSAlex Wilson 	case MAC_STAT_OBYTES:
251ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_rfc_2863_out_octets);
252ebb7c6fdSAlex Wilson 		break;
253ebb7c6fdSAlex Wilson 	default:
254ebb7c6fdSAlex Wilson 		ret = ENOTSUP;
255ebb7c6fdSAlex Wilson 	}
256ebb7c6fdSAlex Wilson 
257ebb7c6fdSAlex Wilson 	return (ret);
258ebb7c6fdSAlex Wilson }
259ebb7c6fdSAlex Wilson 
260ebb7c6fdSAlex Wilson static int
mlxcx_mac_stat_ieee_802_3(mlxcx_t * mlxp,mlxcx_port_t * port,uint_t stat,uint64_t * val)261ebb7c6fdSAlex Wilson mlxcx_mac_stat_ieee_802_3(mlxcx_t *mlxp, mlxcx_port_t *port, uint_t stat,
262ebb7c6fdSAlex Wilson     uint64_t *val)
263ebb7c6fdSAlex Wilson {
264ebb7c6fdSAlex Wilson 	int ret = 0;
265ebb7c6fdSAlex Wilson 	boolean_t ok;
266ebb7c6fdSAlex Wilson 	mlxcx_register_data_t data;
267ebb7c6fdSAlex Wilson 	mlxcx_ppcnt_ieee_802_3_t *st;
268ebb7c6fdSAlex Wilson 
269ebb7c6fdSAlex Wilson 	ASSERT(mutex_owned(&port->mlp_mtx));
270ebb7c6fdSAlex Wilson 
271ebb7c6fdSAlex Wilson 	bzero(&data, sizeof (data));
272ebb7c6fdSAlex Wilson 	data.mlrd_ppcnt.mlrd_ppcnt_local_port = port->mlp_num + 1;
273ebb7c6fdSAlex Wilson 	data.mlrd_ppcnt.mlrd_ppcnt_grp = MLXCX_PPCNT_GRP_IEEE_802_3;
274ebb7c6fdSAlex Wilson 	data.mlrd_ppcnt.mlrd_ppcnt_clear = MLXCX_PPCNT_NO_CLEAR;
275ebb7c6fdSAlex Wilson 
276ebb7c6fdSAlex Wilson 	ok = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ,
277ebb7c6fdSAlex Wilson 	    MLXCX_REG_PPCNT, &data);
278ebb7c6fdSAlex Wilson 	if (!ok)
279ebb7c6fdSAlex Wilson 		return (EIO);
280ebb7c6fdSAlex Wilson 	st = &data.mlrd_ppcnt.mlrd_ppcnt_ieee_802_3;
281ebb7c6fdSAlex Wilson 
282ebb7c6fdSAlex Wilson 	switch (stat) {
283ebb7c6fdSAlex Wilson 	case MAC_STAT_IPACKETS:
284ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_ieee_802_3_frames_rx);
285ebb7c6fdSAlex Wilson 		break;
286ebb7c6fdSAlex Wilson 	case MAC_STAT_OPACKETS:
287ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_ieee_802_3_frames_tx);
288ebb7c6fdSAlex Wilson 		break;
289ebb7c6fdSAlex Wilson 	case ETHER_STAT_ALIGN_ERRORS:
290ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_ieee_802_3_align_err);
291ebb7c6fdSAlex Wilson 		break;
292ebb7c6fdSAlex Wilson 	case ETHER_STAT_FCS_ERRORS:
293ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_ieee_802_3_fcs_err);
294ebb7c6fdSAlex Wilson 		break;
295ebb7c6fdSAlex Wilson 	case ETHER_STAT_TOOLONG_ERRORS:
296ebb7c6fdSAlex Wilson 		*val = from_be64(st->mlppc_ieee_802_3_frame_too_long_err);
297ebb7c6fdSAlex Wilson 		break;
298ebb7c6fdSAlex Wilson 	default:
299ebb7c6fdSAlex Wilson 		ret = ENOTSUP;
300ebb7c6fdSAlex Wilson 	}
301ebb7c6fdSAlex Wilson 
302ebb7c6fdSAlex Wilson 	return (ret);
303ebb7c6fdSAlex Wilson }
304ebb7c6fdSAlex Wilson 
305ebb7c6fdSAlex Wilson static int
mlxcx_mac_stat(void * arg,uint_t stat,uint64_t * val)306ebb7c6fdSAlex Wilson mlxcx_mac_stat(void *arg, uint_t stat, uint64_t *val)
307ebb7c6fdSAlex Wilson {
308ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
309ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = &mlxp->mlx_ports[0];
310ebb7c6fdSAlex Wilson 	int ret = 0;
311ebb7c6fdSAlex Wilson 
312ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
313ebb7c6fdSAlex Wilson 
314ebb7c6fdSAlex Wilson 	switch (stat) {
315ebb7c6fdSAlex Wilson 	case MAC_STAT_IFSPEED:
316*85e4aa97SDan McDonald 		*val = mlxcx_speed_to_bits(port->mlp_oper_proto,
317*85e4aa97SDan McDonald 		    port->mlp_ext_oper_proto);
318ebb7c6fdSAlex Wilson 		break;
319ebb7c6fdSAlex Wilson 	case ETHER_STAT_LINK_DUPLEX:
320ebb7c6fdSAlex Wilson 		*val = LINK_DUPLEX_FULL;
321ebb7c6fdSAlex Wilson 		break;
322ebb7c6fdSAlex Wilson 	case MAC_STAT_RBYTES:
323ebb7c6fdSAlex Wilson 	case MAC_STAT_MULTIRCV:
324ebb7c6fdSAlex Wilson 	case MAC_STAT_BRDCSTRCV:
325ebb7c6fdSAlex Wilson 	case MAC_STAT_MULTIXMT:
326ebb7c6fdSAlex Wilson 	case MAC_STAT_BRDCSTXMT:
327ebb7c6fdSAlex Wilson 	case MAC_STAT_IERRORS:
328ebb7c6fdSAlex Wilson 	case MAC_STAT_UNKNOWNS:
329ebb7c6fdSAlex Wilson 	case MAC_STAT_OERRORS:
330ebb7c6fdSAlex Wilson 	case MAC_STAT_OBYTES:
331ebb7c6fdSAlex Wilson 		ret = mlxcx_mac_stat_rfc_2863(mlxp, port, stat, val);
332ebb7c6fdSAlex Wilson 		break;
333ebb7c6fdSAlex Wilson 	case MAC_STAT_IPACKETS:
334ebb7c6fdSAlex Wilson 	case MAC_STAT_OPACKETS:
335ebb7c6fdSAlex Wilson 	case ETHER_STAT_ALIGN_ERRORS:
336ebb7c6fdSAlex Wilson 	case ETHER_STAT_FCS_ERRORS:
337ebb7c6fdSAlex Wilson 	case ETHER_STAT_TOOLONG_ERRORS:
338ebb7c6fdSAlex Wilson 		ret = mlxcx_mac_stat_ieee_802_3(mlxp, port, stat, val);
339ebb7c6fdSAlex Wilson 		break;
340ebb7c6fdSAlex Wilson 	case MAC_STAT_NORCVBUF:
341ebb7c6fdSAlex Wilson 		*val = port->mlp_stats.mlps_rx_drops;
342ebb7c6fdSAlex Wilson 		break;
343ebb7c6fdSAlex Wilson 	default:
344ebb7c6fdSAlex Wilson 		ret = ENOTSUP;
345ebb7c6fdSAlex Wilson 	}
346ebb7c6fdSAlex Wilson 
347ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
348ebb7c6fdSAlex Wilson 
349ebb7c6fdSAlex Wilson 	return (ret);
350ebb7c6fdSAlex Wilson }
351ebb7c6fdSAlex Wilson 
352ebb7c6fdSAlex Wilson static int
mlxcx_mac_led_set(void * arg,mac_led_mode_t mode,uint_t flags)353ebb7c6fdSAlex Wilson mlxcx_mac_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
354ebb7c6fdSAlex Wilson {
355ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = arg;
356ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = &mlxp->mlx_ports[0];
357ebb7c6fdSAlex Wilson 	int ret = 0;
358ebb7c6fdSAlex Wilson 
359ebb7c6fdSAlex Wilson 	if (flags != 0) {
360ebb7c6fdSAlex Wilson 		return (EINVAL);
361ebb7c6fdSAlex Wilson 	}
362ebb7c6fdSAlex Wilson 
363ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
364ebb7c6fdSAlex Wilson 
365ebb7c6fdSAlex Wilson 	switch (mode) {
366ebb7c6fdSAlex Wilson 	case MAC_LED_DEFAULT:
367ebb7c6fdSAlex Wilson 	case MAC_LED_OFF:
368ebb7c6fdSAlex Wilson 		if (!mlxcx_cmd_set_port_led(mlxp, port, 0)) {
369ebb7c6fdSAlex Wilson 			ret = EIO;
370ebb7c6fdSAlex Wilson 			break;
371ebb7c6fdSAlex Wilson 		}
372ebb7c6fdSAlex Wilson 		break;
373ebb7c6fdSAlex Wilson 	case MAC_LED_IDENT:
374ebb7c6fdSAlex Wilson 		if (!mlxcx_cmd_set_port_led(mlxp, port, UINT16_MAX)) {
375ebb7c6fdSAlex Wilson 			ret = EIO;
376ebb7c6fdSAlex Wilson 			break;
377ebb7c6fdSAlex Wilson 		}
378ebb7c6fdSAlex Wilson 		break;
379ebb7c6fdSAlex Wilson 	default:
380ebb7c6fdSAlex Wilson 		ret = ENOTSUP;
381ebb7c6fdSAlex Wilson 	}
382ebb7c6fdSAlex Wilson 
383ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
384ebb7c6fdSAlex Wilson 
385ebb7c6fdSAlex Wilson 	return (ret);
386ebb7c6fdSAlex Wilson }
387ebb7c6fdSAlex Wilson 
388ebb7c6fdSAlex Wilson static int
mlxcx_mac_txr_info(void * arg,uint_t id,mac_transceiver_info_t * infop)389ebb7c6fdSAlex Wilson mlxcx_mac_txr_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
390ebb7c6fdSAlex Wilson {
391ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = arg;
392ebb7c6fdSAlex Wilson 	mlxcx_module_status_t st;
393ebb7c6fdSAlex Wilson 
394ebb7c6fdSAlex Wilson 	if (!mlxcx_cmd_query_module_status(mlxp, id, &st, NULL))
395ebb7c6fdSAlex Wilson 		return (EIO);
396ebb7c6fdSAlex Wilson 
397ebb7c6fdSAlex Wilson 	if (st != MLXCX_MODULE_UNPLUGGED)
398ebb7c6fdSAlex Wilson 		mac_transceiver_info_set_present(infop, B_TRUE);
399ebb7c6fdSAlex Wilson 
400ebb7c6fdSAlex Wilson 	if (st == MLXCX_MODULE_PLUGGED)
401ebb7c6fdSAlex Wilson 		mac_transceiver_info_set_usable(infop, B_TRUE);
402ebb7c6fdSAlex Wilson 
403ebb7c6fdSAlex Wilson 	return (0);
404ebb7c6fdSAlex Wilson }
405ebb7c6fdSAlex Wilson 
406ebb7c6fdSAlex Wilson static int
mlxcx_mac_txr_read(void * arg,uint_t id,uint_t page,void * vbuf,size_t nbytes,off_t offset,size_t * nread)407ebb7c6fdSAlex Wilson mlxcx_mac_txr_read(void *arg, uint_t id, uint_t page, void *vbuf,
408ebb7c6fdSAlex Wilson     size_t nbytes, off_t offset, size_t *nread)
409ebb7c6fdSAlex Wilson {
410ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = arg;
411ebb7c6fdSAlex Wilson 	mlxcx_register_data_t data;
412ebb7c6fdSAlex Wilson 	uint8_t *buf = vbuf;
413ebb7c6fdSAlex Wilson 	boolean_t ok;
414ebb7c6fdSAlex Wilson 	size_t take, done = 0;
415ebb7c6fdSAlex Wilson 	uint8_t i2c_addr;
416ebb7c6fdSAlex Wilson 
417ebb7c6fdSAlex Wilson 	if (id != 0 || vbuf == NULL || nbytes == 0 || nread == NULL)
418ebb7c6fdSAlex Wilson 		return (EINVAL);
419ebb7c6fdSAlex Wilson 
420ebb7c6fdSAlex Wilson 	if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256))
421ebb7c6fdSAlex Wilson 		return (EINVAL);
422ebb7c6fdSAlex Wilson 
423ebb7c6fdSAlex Wilson 	/*
424ebb7c6fdSAlex Wilson 	 * The PRM is really not very clear about any of this, but it seems
425ebb7c6fdSAlex Wilson 	 * that the i2c_device_addr field in MCIA is the SFP+ spec "page"
426ebb7c6fdSAlex Wilson 	 * number shifted right by 1 bit. They're written in the SFF spec
427ebb7c6fdSAlex Wilson 	 * like "1010000X" so Mellanox just dropped the X.
428ebb7c6fdSAlex Wilson 	 *
429ebb7c6fdSAlex Wilson 	 * This means that if we want page 0xA0, we put 0x50 in the
430ebb7c6fdSAlex Wilson 	 * i2c_device_addr field.
431ebb7c6fdSAlex Wilson 	 *
432ebb7c6fdSAlex Wilson 	 * The "page_number" field in MCIA means something else. Don't ask me
433ebb7c6fdSAlex Wilson 	 * what. FreeBSD leaves it as zero, so we will too!
434ebb7c6fdSAlex Wilson 	 */
435ebb7c6fdSAlex Wilson 	i2c_addr = page >> 1;
436ebb7c6fdSAlex Wilson 
437ebb7c6fdSAlex Wilson 	while (done < nbytes) {
438ebb7c6fdSAlex Wilson 		take = nbytes - done;
439ebb7c6fdSAlex Wilson 		if (take > sizeof (data.mlrd_mcia.mlrd_mcia_data))
440ebb7c6fdSAlex Wilson 			take = sizeof (data.mlrd_mcia.mlrd_mcia_data);
441ebb7c6fdSAlex Wilson 
442ebb7c6fdSAlex Wilson 		bzero(&data, sizeof (data));
443ebb7c6fdSAlex Wilson 		ASSERT3U(id, <=, 0xff);
444ebb7c6fdSAlex Wilson 		data.mlrd_mcia.mlrd_mcia_module = (uint8_t)id;
445ebb7c6fdSAlex Wilson 		data.mlrd_mcia.mlrd_mcia_i2c_device_addr = i2c_addr;
446ebb7c6fdSAlex Wilson 		data.mlrd_mcia.mlrd_mcia_device_addr = to_be16(offset);
447ebb7c6fdSAlex Wilson 		data.mlrd_mcia.mlrd_mcia_size = to_be16(take);
448ebb7c6fdSAlex Wilson 
449ebb7c6fdSAlex Wilson 		ok = mlxcx_cmd_access_register(mlxp,
450ebb7c6fdSAlex Wilson 		    MLXCX_CMD_ACCESS_REGISTER_READ, MLXCX_REG_MCIA, &data);
451ebb7c6fdSAlex Wilson 		if (!ok) {
452ebb7c6fdSAlex Wilson 			*nread = 0;
453ebb7c6fdSAlex Wilson 			return (EIO);
454ebb7c6fdSAlex Wilson 		}
455ebb7c6fdSAlex Wilson 
456ebb7c6fdSAlex Wilson 		if (data.mlrd_mcia.mlrd_mcia_status != MLXCX_MCIA_STATUS_OK) {
457ebb7c6fdSAlex Wilson 			*nread = 0;
458ebb7c6fdSAlex Wilson 			return (EIO);
459ebb7c6fdSAlex Wilson 		}
460ebb7c6fdSAlex Wilson 
461ebb7c6fdSAlex Wilson 		bcopy(data.mlrd_mcia.mlrd_mcia_data, &buf[done], take);
462ebb7c6fdSAlex Wilson 
463ebb7c6fdSAlex Wilson 		done += take;
464ebb7c6fdSAlex Wilson 		offset += take;
465ebb7c6fdSAlex Wilson 	}
466ebb7c6fdSAlex Wilson 	*nread = done;
467ebb7c6fdSAlex Wilson 	return (0);
468ebb7c6fdSAlex Wilson }
469ebb7c6fdSAlex Wilson 
470ebb7c6fdSAlex Wilson static int
mlxcx_mac_ring_stat(mac_ring_driver_t rh,uint_t stat,uint64_t * val)471ebb7c6fdSAlex Wilson mlxcx_mac_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
472ebb7c6fdSAlex Wilson {
473ebb7c6fdSAlex Wilson 	mlxcx_work_queue_t *wq = (mlxcx_work_queue_t *)rh;
474ebb7c6fdSAlex Wilson 	(void) wq;
475ebb7c6fdSAlex Wilson 
476ebb7c6fdSAlex Wilson 	/*
477ebb7c6fdSAlex Wilson 	 * We should add support for using hw flow counters and such to
478ebb7c6fdSAlex Wilson 	 * get per-ring statistics. Not done yet though!
479ebb7c6fdSAlex Wilson 	 */
480ebb7c6fdSAlex Wilson 
481ebb7c6fdSAlex Wilson 	switch (stat) {
482ebb7c6fdSAlex Wilson 	default:
483ebb7c6fdSAlex Wilson 		*val = 0;
484ebb7c6fdSAlex Wilson 		return (ENOTSUP);
485ebb7c6fdSAlex Wilson 	}
486ebb7c6fdSAlex Wilson 
487ebb7c6fdSAlex Wilson 	return (0);
488ebb7c6fdSAlex Wilson }
489ebb7c6fdSAlex Wilson 
490ebb7c6fdSAlex Wilson static int
mlxcx_mac_start(void * arg)491ebb7c6fdSAlex Wilson mlxcx_mac_start(void *arg)
492ebb7c6fdSAlex Wilson {
493ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
494ebb7c6fdSAlex Wilson 	(void) mlxp;
495ebb7c6fdSAlex Wilson 	return (0);
496ebb7c6fdSAlex Wilson }
497ebb7c6fdSAlex Wilson 
498ebb7c6fdSAlex Wilson static void
mlxcx_mac_stop(void * arg)499ebb7c6fdSAlex Wilson mlxcx_mac_stop(void *arg)
500ebb7c6fdSAlex Wilson {
501ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
502ebb7c6fdSAlex Wilson 	(void) mlxp;
503ebb7c6fdSAlex Wilson }
504ebb7c6fdSAlex Wilson 
505ebb7c6fdSAlex Wilson static mblk_t *
mlxcx_mac_ring_tx(void * arg,mblk_t * mp)506ebb7c6fdSAlex Wilson mlxcx_mac_ring_tx(void *arg, mblk_t *mp)
507ebb7c6fdSAlex Wilson {
508ebb7c6fdSAlex Wilson 	mlxcx_work_queue_t *sq = (mlxcx_work_queue_t *)arg;
509ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = sq->mlwq_mlx;
510ebb7c6fdSAlex Wilson 	mlxcx_completion_queue_t *cq;
511ebb7c6fdSAlex Wilson 	mlxcx_buffer_t *b;
512ebb7c6fdSAlex Wilson 	mac_header_info_t mhi;
513ebb7c6fdSAlex Wilson 	mblk_t *kmp, *nmp;
514ebb7c6fdSAlex Wilson 	uint8_t inline_hdrs[MLXCX_MAX_INLINE_HEADERLEN];
515ebb7c6fdSAlex Wilson 	size_t inline_hdrlen, rem, off;
516ebb7c6fdSAlex Wilson 	uint32_t chkflags = 0;
517ebb7c6fdSAlex Wilson 	boolean_t ok;
518ebb7c6fdSAlex Wilson 	size_t take = 0;
51982b4190eSPaul Winder 	uint_t bcount;
520ebb7c6fdSAlex Wilson 
521ebb7c6fdSAlex Wilson 	VERIFY(mp->b_next == NULL);
522ebb7c6fdSAlex Wilson 
523ebb7c6fdSAlex Wilson 	mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &chkflags);
524ebb7c6fdSAlex Wilson 
525ebb7c6fdSAlex Wilson 	if (mac_vlan_header_info(mlxp->mlx_mac_hdl, mp, &mhi) != 0) {
526ebb7c6fdSAlex Wilson 		/*
527ebb7c6fdSAlex Wilson 		 * We got given a frame without a valid L2 header on it. We
528ebb7c6fdSAlex Wilson 		 * can't really transmit that (mlx parts don't like it), so
529ebb7c6fdSAlex Wilson 		 * we will just drop it on the floor.
530ebb7c6fdSAlex Wilson 		 */
531ebb7c6fdSAlex Wilson 		freemsg(mp);
532ebb7c6fdSAlex Wilson 		return (NULL);
533ebb7c6fdSAlex Wilson 	}
534ebb7c6fdSAlex Wilson 
535ebb7c6fdSAlex Wilson 	inline_hdrlen = rem = mhi.mhi_hdrsize;
536ebb7c6fdSAlex Wilson 
537ebb7c6fdSAlex Wilson 	kmp = mp;
538ebb7c6fdSAlex Wilson 	off = 0;
539ebb7c6fdSAlex Wilson 	while (rem > 0) {
540ebb7c6fdSAlex Wilson 		const ptrdiff_t sz = MBLKL(kmp);
541ebb7c6fdSAlex Wilson 		ASSERT3S(sz, >=, 0);
542ebb7c6fdSAlex Wilson 		ASSERT3U(sz, <=, SIZE_MAX);
543ebb7c6fdSAlex Wilson 		take = sz;
544ebb7c6fdSAlex Wilson 		if (take > rem)
545ebb7c6fdSAlex Wilson 			take = rem;
546ebb7c6fdSAlex Wilson 		bcopy(kmp->b_rptr, inline_hdrs + off, take);
547ebb7c6fdSAlex Wilson 		rem -= take;
548ebb7c6fdSAlex Wilson 		off += take;
549ebb7c6fdSAlex Wilson 		if (take == sz) {
550ebb7c6fdSAlex Wilson 			take = 0;
551ebb7c6fdSAlex Wilson 			kmp = kmp->b_cont;
552ebb7c6fdSAlex Wilson 		}
553ebb7c6fdSAlex Wilson 	}
554ebb7c6fdSAlex Wilson 
55582b4190eSPaul Winder 	bcount = mlxcx_buf_bind_or_copy(mlxp, sq, kmp, take, &b);
55682b4190eSPaul Winder 	if (bcount == 0) {
55722d05228SPaul Winder 		atomic_or_uint(&sq->mlwq_state, MLXCX_WQ_BLOCKED_MAC);
55822d05228SPaul Winder 		return (mp);
559ebb7c6fdSAlex Wilson 	}
560ebb7c6fdSAlex Wilson 
561ebb7c6fdSAlex Wilson 	mutex_enter(&sq->mlwq_mtx);
562ebb7c6fdSAlex Wilson 	VERIFY3U(sq->mlwq_inline_mode, <=, MLXCX_ETH_INLINE_L2);
563ebb7c6fdSAlex Wilson 	cq = sq->mlwq_cq;
564ebb7c6fdSAlex Wilson 
565ebb7c6fdSAlex Wilson 	/*
566ebb7c6fdSAlex Wilson 	 * state is a single int, so read-only access without the CQ lock
567ebb7c6fdSAlex Wilson 	 * should be fine.
568ebb7c6fdSAlex Wilson 	 */
569ebb7c6fdSAlex Wilson 	if (cq->mlcq_state & MLXCX_CQ_TEARDOWN) {
570ebb7c6fdSAlex Wilson 		mutex_exit(&sq->mlwq_mtx);
571ebb7c6fdSAlex Wilson 		mlxcx_buf_return_chain(mlxp, b, B_FALSE);
572ebb7c6fdSAlex Wilson 		return (NULL);
573ebb7c6fdSAlex Wilson 	}
574ebb7c6fdSAlex Wilson 
57519325e87SPaul Winder 	if ((sq->mlwq_state & (MLXCX_WQ_TEARDOWN | MLXCX_WQ_STARTED)) !=
57619325e87SPaul Winder 	    MLXCX_WQ_STARTED) {
577ebb7c6fdSAlex Wilson 		mutex_exit(&sq->mlwq_mtx);
578ebb7c6fdSAlex Wilson 		mlxcx_buf_return_chain(mlxp, b, B_FALSE);
579ebb7c6fdSAlex Wilson 		return (NULL);
580ebb7c6fdSAlex Wilson 	}
581ebb7c6fdSAlex Wilson 
582ebb7c6fdSAlex Wilson 	/*
58382b4190eSPaul Winder 	 * If the completion queue buffer count is already at or above
58482b4190eSPaul Winder 	 * the high water mark, or the addition of this new chain will
58582b4190eSPaul Winder 	 * exceed the CQ ring size, then indicate we are blocked.
586ebb7c6fdSAlex Wilson 	 */
58782b4190eSPaul Winder 	if (cq->mlcq_bufcnt >= cq->mlcq_bufhwm ||
58882b4190eSPaul Winder 	    (cq->mlcq_bufcnt + bcount) > cq->mlcq_nents) {
589ebb7c6fdSAlex Wilson 		atomic_or_uint(&cq->mlcq_state, MLXCX_CQ_BLOCKED_MAC);
59022d05228SPaul Winder 		goto blocked;
59122d05228SPaul Winder 	}
59222d05228SPaul Winder 
59322d05228SPaul Winder 	if (sq->mlwq_wqebb_used >= sq->mlwq_bufhwm) {
59422d05228SPaul Winder 		atomic_or_uint(&sq->mlwq_state, MLXCX_WQ_BLOCKED_MAC);
59522d05228SPaul Winder 		goto blocked;
596ebb7c6fdSAlex Wilson 	}
597ebb7c6fdSAlex Wilson 
598ebb7c6fdSAlex Wilson 	ok = mlxcx_sq_add_buffer(mlxp, sq, inline_hdrs, inline_hdrlen,
599ebb7c6fdSAlex Wilson 	    chkflags, b);
600ebb7c6fdSAlex Wilson 	if (!ok) {
601ebb7c6fdSAlex Wilson 		atomic_or_uint(&cq->mlcq_state, MLXCX_CQ_BLOCKED_MAC);
60222d05228SPaul Winder 		atomic_or_uint(&sq->mlwq_state, MLXCX_WQ_BLOCKED_MAC);
60322d05228SPaul Winder 		goto blocked;
604ebb7c6fdSAlex Wilson 	}
605ebb7c6fdSAlex Wilson 
606ebb7c6fdSAlex Wilson 	/*
607ebb7c6fdSAlex Wilson 	 * Now that we've successfully enqueued the rest of the packet,
608ebb7c6fdSAlex Wilson 	 * free any mblks that we cut off while inlining headers.
609ebb7c6fdSAlex Wilson 	 */
610ebb7c6fdSAlex Wilson 	for (; mp != kmp; mp = nmp) {
611ebb7c6fdSAlex Wilson 		nmp = mp->b_cont;
612ebb7c6fdSAlex Wilson 		freeb(mp);
613ebb7c6fdSAlex Wilson 	}
614ebb7c6fdSAlex Wilson 
615ebb7c6fdSAlex Wilson 	mutex_exit(&sq->mlwq_mtx);
616ebb7c6fdSAlex Wilson 
617ebb7c6fdSAlex Wilson 	return (NULL);
61822d05228SPaul Winder 
61922d05228SPaul Winder blocked:
62022d05228SPaul Winder 	mutex_exit(&sq->mlwq_mtx);
62122d05228SPaul Winder 	mlxcx_buf_return_chain(mlxp, b, B_TRUE);
62222d05228SPaul Winder 	return (mp);
623ebb7c6fdSAlex Wilson }
624ebb7c6fdSAlex Wilson 
625ebb7c6fdSAlex Wilson static int
mlxcx_mac_setpromisc(void * arg,boolean_t on)626ebb7c6fdSAlex Wilson mlxcx_mac_setpromisc(void *arg, boolean_t on)
627ebb7c6fdSAlex Wilson {
628ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
629ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = &mlxp->mlx_ports[0];
630ebb7c6fdSAlex Wilson 	mlxcx_flow_group_t *fg;
631ebb7c6fdSAlex Wilson 	mlxcx_flow_entry_t *fe;
632ebb7c6fdSAlex Wilson 	mlxcx_flow_table_t *ft;
633ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g;
634ebb7c6fdSAlex Wilson 	int ret = 0;
635ebb7c6fdSAlex Wilson 	uint_t idx;
636ebb7c6fdSAlex Wilson 
637ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
638ebb7c6fdSAlex Wilson 
639ebb7c6fdSAlex Wilson 	/*
640ebb7c6fdSAlex Wilson 	 * First, do the top-level flow entry on the root flow table for
641ebb7c6fdSAlex Wilson 	 * the port. This catches all traffic that doesn't match any MAC
642ebb7c6fdSAlex Wilson 	 * MAC filters.
643ebb7c6fdSAlex Wilson 	 */
644ebb7c6fdSAlex Wilson 	ft = port->mlp_rx_flow;
645ebb7c6fdSAlex Wilson 	mutex_enter(&ft->mlft_mtx);
646ebb7c6fdSAlex Wilson 	fg = port->mlp_promisc;
647ebb7c6fdSAlex Wilson 	fe = list_head(&fg->mlfg_entries);
648ebb7c6fdSAlex Wilson 	if (on && !(fe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED)) {
649ebb7c6fdSAlex Wilson 		if (!mlxcx_cmd_set_flow_table_entry(mlxp, fe)) {
650ebb7c6fdSAlex Wilson 			ret = EIO;
651ebb7c6fdSAlex Wilson 		}
652ebb7c6fdSAlex Wilson 	} else if (!on && (fe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED)) {
653ebb7c6fdSAlex Wilson 		if (!mlxcx_cmd_delete_flow_table_entry(mlxp, fe)) {
654ebb7c6fdSAlex Wilson 			ret = EIO;
655ebb7c6fdSAlex Wilson 		}
656ebb7c6fdSAlex Wilson 	}
657ebb7c6fdSAlex Wilson 	mutex_exit(&ft->mlft_mtx);
658ebb7c6fdSAlex Wilson 
659ebb7c6fdSAlex Wilson 	/*
660ebb7c6fdSAlex Wilson 	 * If we failed to change the top-level entry, don't bother with
661ebb7c6fdSAlex Wilson 	 * trying the per-group ones.
662ebb7c6fdSAlex Wilson 	 */
663ebb7c6fdSAlex Wilson 	if (ret != 0) {
664ebb7c6fdSAlex Wilson 		mutex_exit(&port->mlp_mtx);
665ebb7c6fdSAlex Wilson 		return (ret);
666ebb7c6fdSAlex Wilson 	}
667ebb7c6fdSAlex Wilson 
668ebb7c6fdSAlex Wilson 	/*
669ebb7c6fdSAlex Wilson 	 * Then, do the per-rx-group flow entries which catch traffic that
670ebb7c6fdSAlex Wilson 	 * matched a MAC filter but failed to match a VLAN filter.
671ebb7c6fdSAlex Wilson 	 */
672ebb7c6fdSAlex Wilson 	for (idx = 0; idx < mlxp->mlx_rx_ngroups; ++idx) {
673ebb7c6fdSAlex Wilson 		g = &mlxp->mlx_rx_groups[idx];
674ebb7c6fdSAlex Wilson 
675ebb7c6fdSAlex Wilson 		mutex_enter(&g->mlg_mtx);
676ebb7c6fdSAlex Wilson 
677ebb7c6fdSAlex Wilson 		ft = g->mlg_rx_vlan_ft;
678ebb7c6fdSAlex Wilson 		mutex_enter(&ft->mlft_mtx);
679ebb7c6fdSAlex Wilson 
680ebb7c6fdSAlex Wilson 		fg = g->mlg_rx_vlan_promisc_fg;
681ebb7c6fdSAlex Wilson 		fe = list_head(&fg->mlfg_entries);
682ebb7c6fdSAlex Wilson 		if (on && !(fe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED)) {
683ebb7c6fdSAlex Wilson 			if (!mlxcx_cmd_set_flow_table_entry(mlxp, fe)) {
684ebb7c6fdSAlex Wilson 				ret = EIO;
685ebb7c6fdSAlex Wilson 			}
686ebb7c6fdSAlex Wilson 		} else if (!on && (fe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED)) {
687ebb7c6fdSAlex Wilson 			if (!mlxcx_cmd_delete_flow_table_entry(mlxp, fe)) {
688ebb7c6fdSAlex Wilson 				ret = EIO;
689ebb7c6fdSAlex Wilson 			}
690ebb7c6fdSAlex Wilson 		}
691ebb7c6fdSAlex Wilson 
692ebb7c6fdSAlex Wilson 		mutex_exit(&ft->mlft_mtx);
693ebb7c6fdSAlex Wilson 		mutex_exit(&g->mlg_mtx);
694ebb7c6fdSAlex Wilson 	}
695ebb7c6fdSAlex Wilson 
696ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
697ebb7c6fdSAlex Wilson 	return (ret);
698ebb7c6fdSAlex Wilson }
699ebb7c6fdSAlex Wilson 
700ebb7c6fdSAlex Wilson static int
mlxcx_mac_multicast(void * arg,boolean_t add,const uint8_t * addr)701ebb7c6fdSAlex Wilson mlxcx_mac_multicast(void *arg, boolean_t add, const uint8_t *addr)
702ebb7c6fdSAlex Wilson {
703ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
704ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = &mlxp->mlx_ports[0];
705ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g = &mlxp->mlx_rx_groups[0];
706ebb7c6fdSAlex Wilson 	int ret = 0;
707ebb7c6fdSAlex Wilson 
708ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
709ebb7c6fdSAlex Wilson 	mutex_enter(&g->mlg_mtx);
710ebb7c6fdSAlex Wilson 	if (add) {
711ebb7c6fdSAlex Wilson 		if (!mlxcx_add_umcast_entry(mlxp, port, g, addr)) {
712ebb7c6fdSAlex Wilson 			ret = EIO;
713ebb7c6fdSAlex Wilson 		}
714ebb7c6fdSAlex Wilson 	} else {
715ebb7c6fdSAlex Wilson 		if (!mlxcx_remove_umcast_entry(mlxp, port, g, addr)) {
716ebb7c6fdSAlex Wilson 			ret = EIO;
717ebb7c6fdSAlex Wilson 		}
718ebb7c6fdSAlex Wilson 	}
719ebb7c6fdSAlex Wilson 	mutex_exit(&g->mlg_mtx);
720ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
721ebb7c6fdSAlex Wilson 	return (ret);
722ebb7c6fdSAlex Wilson }
723ebb7c6fdSAlex Wilson 
724ebb7c6fdSAlex Wilson static int
mlxcx_group_add_mac(void * arg,const uint8_t * mac_addr)725ebb7c6fdSAlex Wilson mlxcx_group_add_mac(void *arg, const uint8_t *mac_addr)
726ebb7c6fdSAlex Wilson {
727ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g = arg;
728ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = g->mlg_mlx;
729ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = g->mlg_port;
730ebb7c6fdSAlex Wilson 	int ret = 0;
731ebb7c6fdSAlex Wilson 
732ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
733ebb7c6fdSAlex Wilson 	mutex_enter(&g->mlg_mtx);
734ebb7c6fdSAlex Wilson 	if (!mlxcx_add_umcast_entry(mlxp, port, g, mac_addr)) {
735ebb7c6fdSAlex Wilson 		ret = EIO;
736ebb7c6fdSAlex Wilson 	}
737ebb7c6fdSAlex Wilson 	mutex_exit(&g->mlg_mtx);
738ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
739ebb7c6fdSAlex Wilson 
740ebb7c6fdSAlex Wilson 	return (ret);
741ebb7c6fdSAlex Wilson }
742ebb7c6fdSAlex Wilson 
743ebb7c6fdSAlex Wilson static int
mlxcx_group_add_vlan(mac_group_driver_t gh,uint16_t vid)744ebb7c6fdSAlex Wilson mlxcx_group_add_vlan(mac_group_driver_t gh, uint16_t vid)
745ebb7c6fdSAlex Wilson {
746ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g = (mlxcx_ring_group_t *)gh;
747ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = g->mlg_mlx;
748ebb7c6fdSAlex Wilson 	int ret = 0;
749ebb7c6fdSAlex Wilson 	boolean_t tagged = B_TRUE;
750ebb7c6fdSAlex Wilson 
751ebb7c6fdSAlex Wilson 	if (vid == MAC_VLAN_UNTAGGED) {
752ebb7c6fdSAlex Wilson 		vid = 0;
753ebb7c6fdSAlex Wilson 		tagged = B_FALSE;
754ebb7c6fdSAlex Wilson 	}
755ebb7c6fdSAlex Wilson 
756ebb7c6fdSAlex Wilson 	mutex_enter(&g->mlg_mtx);
757ebb7c6fdSAlex Wilson 	if (!mlxcx_add_vlan_entry(mlxp, g, tagged, vid)) {
758ebb7c6fdSAlex Wilson 		ret = EIO;
759ebb7c6fdSAlex Wilson 	}
760ebb7c6fdSAlex Wilson 	mutex_exit(&g->mlg_mtx);
761ebb7c6fdSAlex Wilson 
762ebb7c6fdSAlex Wilson 	return (ret);
763ebb7c6fdSAlex Wilson }
764ebb7c6fdSAlex Wilson 
765ebb7c6fdSAlex Wilson static int
mlxcx_group_remove_vlan(mac_group_driver_t gh,uint16_t vid)766ebb7c6fdSAlex Wilson mlxcx_group_remove_vlan(mac_group_driver_t gh, uint16_t vid)
767ebb7c6fdSAlex Wilson {
768ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g = (mlxcx_ring_group_t *)gh;
769ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = g->mlg_mlx;
770ebb7c6fdSAlex Wilson 	int ret = 0;
771ebb7c6fdSAlex Wilson 	boolean_t tagged = B_TRUE;
772ebb7c6fdSAlex Wilson 
773ebb7c6fdSAlex Wilson 	if (vid == MAC_VLAN_UNTAGGED) {
774ebb7c6fdSAlex Wilson 		vid = 0;
775ebb7c6fdSAlex Wilson 		tagged = B_FALSE;
776ebb7c6fdSAlex Wilson 	}
777ebb7c6fdSAlex Wilson 
778ebb7c6fdSAlex Wilson 	mutex_enter(&g->mlg_mtx);
779ebb7c6fdSAlex Wilson 	if (!mlxcx_remove_vlan_entry(mlxp, g, tagged, vid)) {
780ebb7c6fdSAlex Wilson 		ret = EIO;
781ebb7c6fdSAlex Wilson 	}
782ebb7c6fdSAlex Wilson 	mutex_exit(&g->mlg_mtx);
783ebb7c6fdSAlex Wilson 
784ebb7c6fdSAlex Wilson 	return (ret);
785ebb7c6fdSAlex Wilson }
786ebb7c6fdSAlex Wilson 
787ebb7c6fdSAlex Wilson static int
mlxcx_group_remove_mac(void * arg,const uint8_t * mac_addr)788ebb7c6fdSAlex Wilson mlxcx_group_remove_mac(void *arg, const uint8_t *mac_addr)
789ebb7c6fdSAlex Wilson {
790ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g = arg;
791ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = g->mlg_mlx;
792ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = g->mlg_port;
793ebb7c6fdSAlex Wilson 	int ret = 0;
794ebb7c6fdSAlex Wilson 
795ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
796ebb7c6fdSAlex Wilson 	mutex_enter(&g->mlg_mtx);
797ebb7c6fdSAlex Wilson 	if (!mlxcx_remove_umcast_entry(mlxp, port, g, mac_addr)) {
798ebb7c6fdSAlex Wilson 		ret = EIO;
799ebb7c6fdSAlex Wilson 	}
800ebb7c6fdSAlex Wilson 	mutex_exit(&g->mlg_mtx);
801ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
802ebb7c6fdSAlex Wilson 
803ebb7c6fdSAlex Wilson 	return (ret);
804ebb7c6fdSAlex Wilson }
805ebb7c6fdSAlex Wilson 
806ebb7c6fdSAlex Wilson static int
mlxcx_mac_ring_start(mac_ring_driver_t rh,uint64_t gen_num)807ebb7c6fdSAlex Wilson mlxcx_mac_ring_start(mac_ring_driver_t rh, uint64_t gen_num)
808ebb7c6fdSAlex Wilson {
809ebb7c6fdSAlex Wilson 	mlxcx_work_queue_t *wq = (mlxcx_work_queue_t *)rh;
810ebb7c6fdSAlex Wilson 	mlxcx_completion_queue_t *cq = wq->mlwq_cq;
811ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g = wq->mlwq_group;
812ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = wq->mlwq_mlx;
813ebb7c6fdSAlex Wilson 
814ebb7c6fdSAlex Wilson 	ASSERT(cq != NULL);
815ebb7c6fdSAlex Wilson 	ASSERT(g != NULL);
816ebb7c6fdSAlex Wilson 
817ebb7c6fdSAlex Wilson 	ASSERT(wq->mlwq_type == MLXCX_WQ_TYPE_SENDQ ||
818ebb7c6fdSAlex Wilson 	    wq->mlwq_type == MLXCX_WQ_TYPE_RECVQ);
819ebb7c6fdSAlex Wilson 	if (wq->mlwq_type == MLXCX_WQ_TYPE_SENDQ &&
820ebb7c6fdSAlex Wilson 	    !mlxcx_tx_ring_start(mlxp, g, wq))
821ebb7c6fdSAlex Wilson 		return (EIO);
822ebb7c6fdSAlex Wilson 	if (wq->mlwq_type == MLXCX_WQ_TYPE_RECVQ &&
823ebb7c6fdSAlex Wilson 	    !mlxcx_rx_ring_start(mlxp, g, wq))
824ebb7c6fdSAlex Wilson 		return (EIO);
825ebb7c6fdSAlex Wilson 
826ebb7c6fdSAlex Wilson 	mutex_enter(&cq->mlcq_mtx);
827ebb7c6fdSAlex Wilson 	cq->mlcq_mac_gen = gen_num;
828ebb7c6fdSAlex Wilson 	mutex_exit(&cq->mlcq_mtx);
829ebb7c6fdSAlex Wilson 
830ebb7c6fdSAlex Wilson 	return (0);
831ebb7c6fdSAlex Wilson }
832ebb7c6fdSAlex Wilson 
833ebb7c6fdSAlex Wilson static void
mlxcx_mac_ring_stop(mac_ring_driver_t rh)834ebb7c6fdSAlex Wilson mlxcx_mac_ring_stop(mac_ring_driver_t rh)
835ebb7c6fdSAlex Wilson {
836ebb7c6fdSAlex Wilson 	mlxcx_work_queue_t *wq = (mlxcx_work_queue_t *)rh;
837ebb7c6fdSAlex Wilson 	mlxcx_completion_queue_t *cq = wq->mlwq_cq;
838ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = wq->mlwq_mlx;
839ebb7c6fdSAlex Wilson 	mlxcx_buf_shard_t *s;
840ebb7c6fdSAlex Wilson 	mlxcx_buffer_t *buf;
841ebb7c6fdSAlex Wilson 
84219325e87SPaul Winder 	/*
84319325e87SPaul Winder 	 * To prevent deadlocks and sleeping whilst holding either the
84419325e87SPaul Winder 	 * CQ mutex or WQ mutex, we split the stop processing into two
84519325e87SPaul Winder 	 * parts.
84619325e87SPaul Winder 	 *
84719325e87SPaul Winder 	 * With the CQ amd WQ mutexes held the appropriate WQ is stopped.
84819325e87SPaul Winder 	 * The Q in the HCA is set to Reset state and flagged as no
84919325e87SPaul Winder 	 * longer started. Atomic with changing this WQ state, the buffer
85019325e87SPaul Winder 	 * shards are flagged as draining.
85119325e87SPaul Winder 	 *
85219325e87SPaul Winder 	 * Now, any requests for buffers and attempts to submit messages
85319325e87SPaul Winder 	 * will fail and once we're in this state it is safe to relinquish
85419325e87SPaul Winder 	 * the CQ and WQ mutexes. Allowing us to complete the ring stop
85519325e87SPaul Winder 	 * by waiting for the buffer lists, with the exception of
85619325e87SPaul Winder 	 * the loaned list, to drain. Buffers on the loaned list are
85719325e87SPaul Winder 	 * not under our control, we will get them back when the mblk tied
85819325e87SPaul Winder 	 * to the buffer is freed.
85919325e87SPaul Winder 	 */
86019325e87SPaul Winder 
861ebb7c6fdSAlex Wilson 	mutex_enter(&cq->mlcq_mtx);
862ebb7c6fdSAlex Wilson 	mutex_enter(&wq->mlwq_mtx);
86319325e87SPaul Winder 
864ebb7c6fdSAlex Wilson 	if (wq->mlwq_state & MLXCX_WQ_STARTED) {
865ebb7c6fdSAlex Wilson 		if (wq->mlwq_type == MLXCX_WQ_TYPE_RECVQ &&
866ebb7c6fdSAlex Wilson 		    !mlxcx_cmd_stop_rq(mlxp, wq)) {
867ebb7c6fdSAlex Wilson 			mutex_exit(&wq->mlwq_mtx);
868ebb7c6fdSAlex Wilson 			mutex_exit(&cq->mlcq_mtx);
869ebb7c6fdSAlex Wilson 			return;
870ebb7c6fdSAlex Wilson 		}
871ebb7c6fdSAlex Wilson 		if (wq->mlwq_type == MLXCX_WQ_TYPE_SENDQ &&
872ebb7c6fdSAlex Wilson 		    !mlxcx_cmd_stop_sq(mlxp, wq)) {
873ebb7c6fdSAlex Wilson 			mutex_exit(&wq->mlwq_mtx);
874ebb7c6fdSAlex Wilson 			mutex_exit(&cq->mlcq_mtx);
875ebb7c6fdSAlex Wilson 			return;
876ebb7c6fdSAlex Wilson 		}
877ebb7c6fdSAlex Wilson 	}
878ebb7c6fdSAlex Wilson 	ASSERT0(wq->mlwq_state & MLXCX_WQ_STARTED);
879ebb7c6fdSAlex Wilson 
88019325e87SPaul Winder 	mlxcx_shard_draining(wq->mlwq_bufs);
88119325e87SPaul Winder 	if (wq->mlwq_foreign_bufs != NULL)
88219325e87SPaul Winder 		mlxcx_shard_draining(wq->mlwq_foreign_bufs);
88319325e87SPaul Winder 
88419325e87SPaul Winder 
885ebb7c6fdSAlex Wilson 	if (wq->mlwq_state & MLXCX_WQ_BUFFERS) {
886e1447ca9SPaul Winder 		list_t cq_buffers;
887e1447ca9SPaul Winder 
888e1447ca9SPaul Winder 		/*
889e1447ca9SPaul Winder 		 * Take the buffers away from the CQ. If the CQ is being
890e1447ca9SPaul Winder 		 * processed and the WQ has been stopped, a completion
891e1447ca9SPaul Winder 		 * which does not match to a buffer will be ignored.
892e1447ca9SPaul Winder 		 */
893e1447ca9SPaul Winder 		list_create(&cq_buffers, sizeof (mlxcx_buffer_t),
894e1447ca9SPaul Winder 		    offsetof(mlxcx_buffer_t, mlb_cq_entry));
895e1447ca9SPaul Winder 
896e1447ca9SPaul Winder 		list_move_tail(&cq_buffers, &cq->mlcq_buffers);
897e1447ca9SPaul Winder 
898e1447ca9SPaul Winder 		mutex_enter(&cq->mlcq_bufbmtx);
899e1447ca9SPaul Winder 		list_move_tail(&cq_buffers, &cq->mlcq_buffers_b);
900e1447ca9SPaul Winder 		mutex_exit(&cq->mlcq_bufbmtx);
901e1447ca9SPaul Winder 
902e1447ca9SPaul Winder 		cq->mlcq_bufcnt = 0;
903e1447ca9SPaul Winder 
90419325e87SPaul Winder 		mutex_exit(&wq->mlwq_mtx);
90519325e87SPaul Winder 		mutex_exit(&cq->mlcq_mtx);
90619325e87SPaul Winder 
907ebb7c6fdSAlex Wilson 		/* Return any outstanding buffers to the free pool. */
908e1447ca9SPaul Winder 		while ((buf = list_remove_head(&cq_buffers)) != NULL) {
909ebb7c6fdSAlex Wilson 			mlxcx_buf_return_chain(mlxp, buf, B_FALSE);
910ebb7c6fdSAlex Wilson 		}
911e1447ca9SPaul Winder 		list_destroy(&cq_buffers);
912ebb7c6fdSAlex Wilson 
913ebb7c6fdSAlex Wilson 		s = wq->mlwq_bufs;
914ebb7c6fdSAlex Wilson 		mutex_enter(&s->mlbs_mtx);
915ebb7c6fdSAlex Wilson 		while (!list_is_empty(&s->mlbs_busy))
916ebb7c6fdSAlex Wilson 			cv_wait(&s->mlbs_free_nonempty, &s->mlbs_mtx);
917ebb7c6fdSAlex Wilson 		while ((buf = list_head(&s->mlbs_free)) != NULL) {
918ebb7c6fdSAlex Wilson 			mlxcx_buf_destroy(mlxp, buf);
919ebb7c6fdSAlex Wilson 		}
920ebb7c6fdSAlex Wilson 		mutex_exit(&s->mlbs_mtx);
921ebb7c6fdSAlex Wilson 
922ebb7c6fdSAlex Wilson 		s = wq->mlwq_foreign_bufs;
923ebb7c6fdSAlex Wilson 		if (s != NULL) {
924ebb7c6fdSAlex Wilson 			mutex_enter(&s->mlbs_mtx);
925ebb7c6fdSAlex Wilson 			while (!list_is_empty(&s->mlbs_busy))
926ebb7c6fdSAlex Wilson 				cv_wait(&s->mlbs_free_nonempty, &s->mlbs_mtx);
927ebb7c6fdSAlex Wilson 			while ((buf = list_head(&s->mlbs_free)) != NULL) {
928ebb7c6fdSAlex Wilson 				mlxcx_buf_destroy(mlxp, buf);
929ebb7c6fdSAlex Wilson 			}
930ebb7c6fdSAlex Wilson 			mutex_exit(&s->mlbs_mtx);
931ebb7c6fdSAlex Wilson 		}
932ebb7c6fdSAlex Wilson 
93319325e87SPaul Winder 		mutex_enter(&wq->mlwq_mtx);
934ebb7c6fdSAlex Wilson 		wq->mlwq_state &= ~MLXCX_WQ_BUFFERS;
93519325e87SPaul Winder 		mutex_exit(&wq->mlwq_mtx);
93619325e87SPaul Winder 	} else {
93719325e87SPaul Winder 		mutex_exit(&wq->mlwq_mtx);
93819325e87SPaul Winder 		mutex_exit(&cq->mlcq_mtx);
939ebb7c6fdSAlex Wilson 	}
940ebb7c6fdSAlex Wilson }
941ebb7c6fdSAlex Wilson 
942ebb7c6fdSAlex Wilson static int
mlxcx_mac_group_start(mac_group_driver_t gh)943ebb7c6fdSAlex Wilson mlxcx_mac_group_start(mac_group_driver_t gh)
944ebb7c6fdSAlex Wilson {
945ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g = (mlxcx_ring_group_t *)gh;
946ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = g->mlg_mlx;
947ebb7c6fdSAlex Wilson 
948ebb7c6fdSAlex Wilson 	VERIFY3S(g->mlg_type, ==, MLXCX_GROUP_RX);
949ebb7c6fdSAlex Wilson 	ASSERT(mlxp != NULL);
950ebb7c6fdSAlex Wilson 
951ebb7c6fdSAlex Wilson 	if (g->mlg_state & MLXCX_GROUP_RUNNING)
952ebb7c6fdSAlex Wilson 		return (0);
953ebb7c6fdSAlex Wilson 
954ebb7c6fdSAlex Wilson 	if (!mlxcx_rx_group_start(mlxp, g))
955ebb7c6fdSAlex Wilson 		return (EIO);
956ebb7c6fdSAlex Wilson 
957ebb7c6fdSAlex Wilson 	return (0);
958ebb7c6fdSAlex Wilson }
959ebb7c6fdSAlex Wilson 
960ebb7c6fdSAlex Wilson static void
mlxcx_mac_fill_tx_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)961ebb7c6fdSAlex Wilson mlxcx_mac_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
962ebb7c6fdSAlex Wilson     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
963ebb7c6fdSAlex Wilson {
964ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
965ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g;
966ebb7c6fdSAlex Wilson 	mlxcx_work_queue_t *wq;
967ebb7c6fdSAlex Wilson 	mac_intr_t *mintr = &infop->mri_intr;
968ebb7c6fdSAlex Wilson 
969ebb7c6fdSAlex Wilson 	if (rtype != MAC_RING_TYPE_TX)
970ebb7c6fdSAlex Wilson 		return;
971ebb7c6fdSAlex Wilson 	ASSERT3S(group_index, ==, -1);
972ebb7c6fdSAlex Wilson 
973ebb7c6fdSAlex Wilson 	g = &mlxp->mlx_tx_groups[0];
974ebb7c6fdSAlex Wilson 	ASSERT(g->mlg_state & MLXCX_GROUP_INIT);
975ebb7c6fdSAlex Wilson 	mutex_enter(&g->mlg_mtx);
976ebb7c6fdSAlex Wilson 
977ebb7c6fdSAlex Wilson 	ASSERT3S(ring_index, >=, 0);
978ebb7c6fdSAlex Wilson 	ASSERT3S(ring_index, <, g->mlg_nwqs);
979ebb7c6fdSAlex Wilson 
980ebb7c6fdSAlex Wilson 	wq = &g->mlg_wqs[ring_index];
981ebb7c6fdSAlex Wilson 
982ebb7c6fdSAlex Wilson 	wq->mlwq_cq->mlcq_mac_hdl = rh;
983ebb7c6fdSAlex Wilson 
984ebb7c6fdSAlex Wilson 	infop->mri_driver = (mac_ring_driver_t)wq;
985ebb7c6fdSAlex Wilson 	infop->mri_start = mlxcx_mac_ring_start;
986ebb7c6fdSAlex Wilson 	infop->mri_stop = mlxcx_mac_ring_stop;
987ebb7c6fdSAlex Wilson 	infop->mri_tx = mlxcx_mac_ring_tx;
988ebb7c6fdSAlex Wilson 	infop->mri_stat = mlxcx_mac_ring_stat;
989ebb7c6fdSAlex Wilson 
990ebb7c6fdSAlex Wilson 	mintr->mi_ddi_handle = mlxp->mlx_intr_handles[
991ebb7c6fdSAlex Wilson 	    wq->mlwq_cq->mlcq_eq->mleq_intr_index];
992ebb7c6fdSAlex Wilson 
993ebb7c6fdSAlex Wilson 	mutex_exit(&g->mlg_mtx);
994ebb7c6fdSAlex Wilson }
995ebb7c6fdSAlex Wilson 
996ebb7c6fdSAlex Wilson static int
mlxcx_mac_ring_intr_enable(mac_intr_handle_t intrh)997ebb7c6fdSAlex Wilson mlxcx_mac_ring_intr_enable(mac_intr_handle_t intrh)
998ebb7c6fdSAlex Wilson {
999ebb7c6fdSAlex Wilson 	mlxcx_completion_queue_t *cq = (mlxcx_completion_queue_t *)intrh;
1000ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = cq->mlcq_mlx;
1001ebb7c6fdSAlex Wilson 
1002ebb7c6fdSAlex Wilson 	/*
10030207f820SPaul Winder 	 * We are going to call mlxcx_arm_cq() here, so we take the arm lock
1004ebb7c6fdSAlex Wilson 	 * as well as the CQ one to make sure we don't race against
1005ebb7c6fdSAlex Wilson 	 * mlxcx_intr_n().
1006ebb7c6fdSAlex Wilson 	 */
10070207f820SPaul Winder 	mutex_enter(&cq->mlcq_arm_mtx);
1008ebb7c6fdSAlex Wilson 	mutex_enter(&cq->mlcq_mtx);
1009ebb7c6fdSAlex Wilson 	if (cq->mlcq_state & MLXCX_CQ_POLLING) {
10100207f820SPaul Winder 		atomic_and_uint(&cq->mlcq_state, ~MLXCX_CQ_POLLING);
1011ebb7c6fdSAlex Wilson 		if (!(cq->mlcq_state & MLXCX_CQ_ARMED))
1012ebb7c6fdSAlex Wilson 			mlxcx_arm_cq(mlxp, cq);
1013ebb7c6fdSAlex Wilson 	}
1014ebb7c6fdSAlex Wilson 	mutex_exit(&cq->mlcq_mtx);
10150207f820SPaul Winder 	mutex_exit(&cq->mlcq_arm_mtx);
1016ebb7c6fdSAlex Wilson 
1017ebb7c6fdSAlex Wilson 	return (0);
1018ebb7c6fdSAlex Wilson }
1019ebb7c6fdSAlex Wilson 
1020ebb7c6fdSAlex Wilson static int
mlxcx_mac_ring_intr_disable(mac_intr_handle_t intrh)1021ebb7c6fdSAlex Wilson mlxcx_mac_ring_intr_disable(mac_intr_handle_t intrh)
1022ebb7c6fdSAlex Wilson {
1023ebb7c6fdSAlex Wilson 	mlxcx_completion_queue_t *cq = (mlxcx_completion_queue_t *)intrh;
1024ebb7c6fdSAlex Wilson 
1025ebb7c6fdSAlex Wilson 	mutex_enter(&cq->mlcq_mtx);
102622d05228SPaul Winder 	atomic_or_uint(&cq->mlcq_state, MLXCX_CQ_POLLING);
1027ebb7c6fdSAlex Wilson 	mutex_exit(&cq->mlcq_mtx);
1028ebb7c6fdSAlex Wilson 
1029ebb7c6fdSAlex Wilson 	return (0);
1030ebb7c6fdSAlex Wilson }
1031ebb7c6fdSAlex Wilson 
1032ebb7c6fdSAlex Wilson static mblk_t *
mlxcx_mac_ring_rx_poll(void * arg,int poll_bytes)1033ebb7c6fdSAlex Wilson mlxcx_mac_ring_rx_poll(void *arg, int poll_bytes)
1034ebb7c6fdSAlex Wilson {
1035ebb7c6fdSAlex Wilson 	mlxcx_work_queue_t *wq = (mlxcx_work_queue_t *)arg;
1036ebb7c6fdSAlex Wilson 	mlxcx_completion_queue_t *cq = wq->mlwq_cq;
1037ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = wq->mlwq_mlx;
1038ebb7c6fdSAlex Wilson 	mblk_t *mp;
1039ebb7c6fdSAlex Wilson 
1040ebb7c6fdSAlex Wilson 	ASSERT(cq != NULL);
1041ebb7c6fdSAlex Wilson 	ASSERT3S(poll_bytes, >, 0);
1042ebb7c6fdSAlex Wilson 	if (poll_bytes == 0)
1043ebb7c6fdSAlex Wilson 		return (NULL);
1044ebb7c6fdSAlex Wilson 
1045ebb7c6fdSAlex Wilson 	mutex_enter(&cq->mlcq_mtx);
1046ebb7c6fdSAlex Wilson 	mp = mlxcx_rx_poll(mlxp, cq, poll_bytes);
1047ebb7c6fdSAlex Wilson 	mutex_exit(&cq->mlcq_mtx);
1048ebb7c6fdSAlex Wilson 
1049ebb7c6fdSAlex Wilson 	return (mp);
1050ebb7c6fdSAlex Wilson }
1051ebb7c6fdSAlex Wilson 
1052ebb7c6fdSAlex Wilson static void
mlxcx_mac_fill_rx_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)1053ebb7c6fdSAlex Wilson mlxcx_mac_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
1054ebb7c6fdSAlex Wilson     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
1055ebb7c6fdSAlex Wilson {
1056ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
1057ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g;
1058ebb7c6fdSAlex Wilson 	mlxcx_work_queue_t *wq;
1059ebb7c6fdSAlex Wilson 	mac_intr_t *mintr = &infop->mri_intr;
1060ebb7c6fdSAlex Wilson 
1061ebb7c6fdSAlex Wilson 	if (rtype != MAC_RING_TYPE_RX)
1062ebb7c6fdSAlex Wilson 		return;
1063ebb7c6fdSAlex Wilson 	ASSERT3S(group_index, >=, 0);
1064ebb7c6fdSAlex Wilson 	ASSERT3S(group_index, <, mlxp->mlx_rx_ngroups);
1065ebb7c6fdSAlex Wilson 
1066ebb7c6fdSAlex Wilson 	g = &mlxp->mlx_rx_groups[group_index];
1067ebb7c6fdSAlex Wilson 	ASSERT(g->mlg_state & MLXCX_GROUP_INIT);
1068ebb7c6fdSAlex Wilson 	mutex_enter(&g->mlg_mtx);
1069ebb7c6fdSAlex Wilson 
1070ebb7c6fdSAlex Wilson 	ASSERT3S(ring_index, >=, 0);
1071ebb7c6fdSAlex Wilson 	ASSERT3S(ring_index, <, g->mlg_nwqs);
1072ebb7c6fdSAlex Wilson 
1073ebb7c6fdSAlex Wilson 	ASSERT(g->mlg_state & MLXCX_GROUP_WQS);
1074ebb7c6fdSAlex Wilson 	wq = &g->mlg_wqs[ring_index];
1075ebb7c6fdSAlex Wilson 
1076ebb7c6fdSAlex Wilson 	wq->mlwq_cq->mlcq_mac_hdl = rh;
1077ebb7c6fdSAlex Wilson 
1078ebb7c6fdSAlex Wilson 	infop->mri_driver = (mac_ring_driver_t)wq;
1079ebb7c6fdSAlex Wilson 	infop->mri_start = mlxcx_mac_ring_start;
1080ebb7c6fdSAlex Wilson 	infop->mri_stop = mlxcx_mac_ring_stop;
1081ebb7c6fdSAlex Wilson 	infop->mri_poll = mlxcx_mac_ring_rx_poll;
1082ebb7c6fdSAlex Wilson 	infop->mri_stat = mlxcx_mac_ring_stat;
1083ebb7c6fdSAlex Wilson 
1084ebb7c6fdSAlex Wilson 	mintr->mi_handle = (mac_intr_handle_t)wq->mlwq_cq;
1085ebb7c6fdSAlex Wilson 	mintr->mi_enable = mlxcx_mac_ring_intr_enable;
1086ebb7c6fdSAlex Wilson 	mintr->mi_disable = mlxcx_mac_ring_intr_disable;
1087ebb7c6fdSAlex Wilson 
1088ebb7c6fdSAlex Wilson 	mintr->mi_ddi_handle = mlxp->mlx_intr_handles[
1089ebb7c6fdSAlex Wilson 	    wq->mlwq_cq->mlcq_eq->mleq_intr_index];
1090ebb7c6fdSAlex Wilson 
1091ebb7c6fdSAlex Wilson 	mutex_exit(&g->mlg_mtx);
1092ebb7c6fdSAlex Wilson }
1093ebb7c6fdSAlex Wilson 
1094ebb7c6fdSAlex Wilson static void
mlxcx_mac_fill_rx_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)1095ebb7c6fdSAlex Wilson mlxcx_mac_fill_rx_group(void *arg, mac_ring_type_t rtype, const int index,
1096ebb7c6fdSAlex Wilson     mac_group_info_t *infop, mac_group_handle_t gh)
1097ebb7c6fdSAlex Wilson {
1098ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
1099ebb7c6fdSAlex Wilson 	mlxcx_ring_group_t *g;
1100ebb7c6fdSAlex Wilson 
1101ebb7c6fdSAlex Wilson 	if (rtype != MAC_RING_TYPE_RX)
1102ebb7c6fdSAlex Wilson 		return;
1103ebb7c6fdSAlex Wilson 
1104ebb7c6fdSAlex Wilson 	ASSERT3S(index, >=, 0);
1105ebb7c6fdSAlex Wilson 	ASSERT3S(index, <, mlxp->mlx_rx_ngroups);
1106ebb7c6fdSAlex Wilson 	g = &mlxp->mlx_rx_groups[index];
1107ebb7c6fdSAlex Wilson 	ASSERT(g->mlg_state & MLXCX_GROUP_INIT);
1108ebb7c6fdSAlex Wilson 
1109ebb7c6fdSAlex Wilson 	g->mlg_mac_hdl = gh;
1110ebb7c6fdSAlex Wilson 
1111ebb7c6fdSAlex Wilson 	infop->mgi_driver = (mac_group_driver_t)g;
1112ebb7c6fdSAlex Wilson 	infop->mgi_start = mlxcx_mac_group_start;
1113ebb7c6fdSAlex Wilson 	infop->mgi_stop = NULL;
1114ebb7c6fdSAlex Wilson 	infop->mgi_addmac = mlxcx_group_add_mac;
1115ebb7c6fdSAlex Wilson 	infop->mgi_remmac = mlxcx_group_remove_mac;
1116ebb7c6fdSAlex Wilson 	infop->mgi_addvlan = mlxcx_group_add_vlan;
1117ebb7c6fdSAlex Wilson 	infop->mgi_remvlan = mlxcx_group_remove_vlan;
1118ebb7c6fdSAlex Wilson 
1119ebb7c6fdSAlex Wilson 	infop->mgi_count = g->mlg_nwqs;
1120ebb7c6fdSAlex Wilson }
1121ebb7c6fdSAlex Wilson 
1122ebb7c6fdSAlex Wilson static boolean_t
mlxcx_mac_getcapab(void * arg,mac_capab_t cap,void * cap_data)1123ebb7c6fdSAlex Wilson mlxcx_mac_getcapab(void *arg, mac_capab_t cap, void *cap_data)
1124ebb7c6fdSAlex Wilson {
1125ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
1126ebb7c6fdSAlex Wilson 	mac_capab_rings_t *cap_rings;
1127ebb7c6fdSAlex Wilson 	mac_capab_led_t *cap_leds;
1128ebb7c6fdSAlex Wilson 	mac_capab_transceiver_t *cap_txr;
1129ebb7c6fdSAlex Wilson 	uint_t i, n = 0;
1130ebb7c6fdSAlex Wilson 
1131ebb7c6fdSAlex Wilson 	switch (cap) {
1132ebb7c6fdSAlex Wilson 
1133ebb7c6fdSAlex Wilson 	case MAC_CAPAB_RINGS:
1134ebb7c6fdSAlex Wilson 		cap_rings = cap_data;
1135ebb7c6fdSAlex Wilson 		cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
1136ebb7c6fdSAlex Wilson 		switch (cap_rings->mr_type) {
1137ebb7c6fdSAlex Wilson 		case MAC_RING_TYPE_TX:
1138ebb7c6fdSAlex Wilson 			cap_rings->mr_gnum = 0;
1139ebb7c6fdSAlex Wilson 			cap_rings->mr_rnum = mlxp->mlx_tx_groups[0].mlg_nwqs;
1140ebb7c6fdSAlex Wilson 			cap_rings->mr_rget = mlxcx_mac_fill_tx_ring;
1141ebb7c6fdSAlex Wilson 			cap_rings->mr_gget = NULL;
1142ebb7c6fdSAlex Wilson 			cap_rings->mr_gaddring = NULL;
1143ebb7c6fdSAlex Wilson 			cap_rings->mr_gremring = NULL;
1144ebb7c6fdSAlex Wilson 			break;
1145ebb7c6fdSAlex Wilson 		case MAC_RING_TYPE_RX:
1146ebb7c6fdSAlex Wilson 			cap_rings->mr_gnum = mlxp->mlx_rx_ngroups;
1147ebb7c6fdSAlex Wilson 			for (i = 0; i < mlxp->mlx_rx_ngroups; ++i)
1148ebb7c6fdSAlex Wilson 				n += mlxp->mlx_rx_groups[i].mlg_nwqs;
1149ebb7c6fdSAlex Wilson 			cap_rings->mr_rnum = n;
1150ebb7c6fdSAlex Wilson 			cap_rings->mr_rget = mlxcx_mac_fill_rx_ring;
1151ebb7c6fdSAlex Wilson 			cap_rings->mr_gget = mlxcx_mac_fill_rx_group;
1152ebb7c6fdSAlex Wilson 			cap_rings->mr_gaddring = NULL;
1153ebb7c6fdSAlex Wilson 			cap_rings->mr_gremring = NULL;
1154ebb7c6fdSAlex Wilson 			break;
1155ebb7c6fdSAlex Wilson 		default:
1156ebb7c6fdSAlex Wilson 			return (B_FALSE);
1157ebb7c6fdSAlex Wilson 		}
1158ebb7c6fdSAlex Wilson 		break;
1159ebb7c6fdSAlex Wilson 
1160ebb7c6fdSAlex Wilson 	case MAC_CAPAB_HCKSUM:
1161ebb7c6fdSAlex Wilson 		if (mlxp->mlx_caps->mlc_checksum) {
1162ebb7c6fdSAlex Wilson 			*(uint32_t *)cap_data = HCKSUM_INET_FULL_V4 |
1163ebb7c6fdSAlex Wilson 			    HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM;
1164ebb7c6fdSAlex Wilson 		}
1165ebb7c6fdSAlex Wilson 		break;
1166ebb7c6fdSAlex Wilson 
1167ebb7c6fdSAlex Wilson 	case MAC_CAPAB_LED:
1168ebb7c6fdSAlex Wilson 		cap_leds = cap_data;
1169ebb7c6fdSAlex Wilson 
1170ebb7c6fdSAlex Wilson 		cap_leds->mcl_flags = 0;
1171ebb7c6fdSAlex Wilson 		cap_leds->mcl_modes = MAC_LED_DEFAULT | MAC_LED_OFF |
1172ebb7c6fdSAlex Wilson 		    MAC_LED_IDENT;
1173ebb7c6fdSAlex Wilson 		cap_leds->mcl_set = mlxcx_mac_led_set;
1174ebb7c6fdSAlex Wilson 		break;
1175ebb7c6fdSAlex Wilson 
1176ebb7c6fdSAlex Wilson 	case MAC_CAPAB_TRANSCEIVER:
1177ebb7c6fdSAlex Wilson 		cap_txr = cap_data;
1178ebb7c6fdSAlex Wilson 
1179ebb7c6fdSAlex Wilson 		cap_txr->mct_flags = 0;
1180ebb7c6fdSAlex Wilson 		cap_txr->mct_ntransceivers = 1;
1181ebb7c6fdSAlex Wilson 		cap_txr->mct_info = mlxcx_mac_txr_info;
1182ebb7c6fdSAlex Wilson 		cap_txr->mct_read = mlxcx_mac_txr_read;
1183ebb7c6fdSAlex Wilson 		break;
1184ebb7c6fdSAlex Wilson 
1185ebb7c6fdSAlex Wilson 	default:
1186ebb7c6fdSAlex Wilson 		return (B_FALSE);
1187ebb7c6fdSAlex Wilson 	}
1188ebb7c6fdSAlex Wilson 
1189ebb7c6fdSAlex Wilson 	return (B_TRUE);
1190ebb7c6fdSAlex Wilson }
1191ebb7c6fdSAlex Wilson 
1192ebb7c6fdSAlex Wilson static void
mlxcx_mac_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)1193ebb7c6fdSAlex Wilson mlxcx_mac_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1194ebb7c6fdSAlex Wilson     mac_prop_info_handle_t prh)
1195ebb7c6fdSAlex Wilson {
1196ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
1197ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = &mlxp->mlx_ports[0];
1198ebb7c6fdSAlex Wilson 
1199ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
1200ebb7c6fdSAlex Wilson 
1201ebb7c6fdSAlex Wilson 	switch (pr_num) {
1202ebb7c6fdSAlex Wilson 	case MAC_PROP_DUPLEX:
1203ebb7c6fdSAlex Wilson 	case MAC_PROP_SPEED:
1204ebb7c6fdSAlex Wilson 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1205ebb7c6fdSAlex Wilson 		break;
1206ebb7c6fdSAlex Wilson 	case MAC_PROP_MTU:
1207ebb7c6fdSAlex Wilson 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
1208ebb7c6fdSAlex Wilson 		mac_prop_info_set_range_uint32(prh, MLXCX_MTU_OFFSET,
1209ebb7c6fdSAlex Wilson 		    port->mlp_max_mtu);
1210ebb7c6fdSAlex Wilson 		mac_prop_info_set_default_uint32(prh,
1211ebb7c6fdSAlex Wilson 		    port->mlp_mtu - MLXCX_MTU_OFFSET);
1212ebb7c6fdSAlex Wilson 		break;
1213ebb7c6fdSAlex Wilson 	case MAC_PROP_AUTONEG:
1214ebb7c6fdSAlex Wilson 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1215ebb7c6fdSAlex Wilson 		mac_prop_info_set_default_uint8(prh, 1);
1216ebb7c6fdSAlex Wilson 		break;
1217d77e6e0fSPaul Winder 	case MAC_PROP_ADV_FEC_CAP:
1218d77e6e0fSPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1219d77e6e0fSPaul Winder 		mac_prop_info_set_default_fec(prh, LINK_FEC_AUTO);
1220d77e6e0fSPaul Winder 		break;
1221d77e6e0fSPaul Winder 	case MAC_PROP_EN_FEC_CAP:
1222d77e6e0fSPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
1223d77e6e0fSPaul Winder 		mac_prop_info_set_default_fec(prh, LINK_FEC_AUTO);
1224d77e6e0fSPaul Winder 		break;
1225*85e4aa97SDan McDonald 	case MAC_PROP_ADV_400GFDX_CAP:
1226*85e4aa97SDan McDonald 	case MAC_PROP_EN_400GFDX_CAP:
1227*85e4aa97SDan McDonald 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1228*85e4aa97SDan McDonald 		mac_prop_info_set_default_uint8(prh,
1229*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_400G) != 0);
1230*85e4aa97SDan McDonald 		break;
1231*85e4aa97SDan McDonald 	case MAC_PROP_ADV_200GFDX_CAP:
1232*85e4aa97SDan McDonald 	case MAC_PROP_EN_200GFDX_CAP:
1233*85e4aa97SDan McDonald 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1234*85e4aa97SDan McDonald 		mac_prop_info_set_default_uint8(prh,
1235*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_200G) != 0);
1236*85e4aa97SDan McDonald 		break;
12378b11ca88SPaul Winder 	case MAC_PROP_ADV_100GFDX_CAP:
12388b11ca88SPaul Winder 	case MAC_PROP_EN_100GFDX_CAP:
12398b11ca88SPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
12408b11ca88SPaul Winder 		mac_prop_info_set_default_uint8(prh,
1241*85e4aa97SDan McDonald 		    ((port->mlp_oper_proto & MLXCX_PROTO_100G) != 0 ||
1242*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_100G)) != 0);
12438b11ca88SPaul Winder 		break;
12448b11ca88SPaul Winder 	case MAC_PROP_ADV_50GFDX_CAP:
12458b11ca88SPaul Winder 	case MAC_PROP_EN_50GFDX_CAP:
12468b11ca88SPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
12478b11ca88SPaul Winder 		mac_prop_info_set_default_uint8(prh,
1248*85e4aa97SDan McDonald 		    ((port->mlp_oper_proto & MLXCX_PROTO_50G) != 0 ||
1249*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_50G)) != 0);
12508b11ca88SPaul Winder 		break;
12518b11ca88SPaul Winder 	case MAC_PROP_ADV_40GFDX_CAP:
12528b11ca88SPaul Winder 	case MAC_PROP_EN_40GFDX_CAP:
12538b11ca88SPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
12548b11ca88SPaul Winder 		mac_prop_info_set_default_uint8(prh,
1255*85e4aa97SDan McDonald 		    ((port->mlp_oper_proto & MLXCX_PROTO_40G) != 0 ||
1256*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_40G)) != 0);
12578b11ca88SPaul Winder 		break;
12588b11ca88SPaul Winder 	case MAC_PROP_ADV_25GFDX_CAP:
12598b11ca88SPaul Winder 	case MAC_PROP_EN_25GFDX_CAP:
12608b11ca88SPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
12618b11ca88SPaul Winder 		mac_prop_info_set_default_uint8(prh,
1262*85e4aa97SDan McDonald 		    ((port->mlp_oper_proto & MLXCX_PROTO_25G) != 0 ||
1263*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_25G)) != 0);
12648b11ca88SPaul Winder 		break;
12658b11ca88SPaul Winder 	case MAC_PROP_ADV_10GFDX_CAP:
12668b11ca88SPaul Winder 	case MAC_PROP_EN_10GFDX_CAP:
12678b11ca88SPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
12688b11ca88SPaul Winder 		mac_prop_info_set_default_uint8(prh,
1269*85e4aa97SDan McDonald 		    ((port->mlp_oper_proto & MLXCX_PROTO_10G) != 0 ||
1270*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_10G)) != 0);
12718b11ca88SPaul Winder 		break;
12728b11ca88SPaul Winder 	case MAC_PROP_ADV_1000FDX_CAP:
12738b11ca88SPaul Winder 	case MAC_PROP_EN_1000FDX_CAP:
12748b11ca88SPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
12758b11ca88SPaul Winder 		mac_prop_info_set_default_uint8(prh,
1276*85e4aa97SDan McDonald 		    ((port->mlp_oper_proto & MLXCX_PROTO_1G) != 0 ||
1277*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_1G)) != 0);
12788b11ca88SPaul Winder 		break;
12798b11ca88SPaul Winder 	case MAC_PROP_ADV_100FDX_CAP:
12808b11ca88SPaul Winder 	case MAC_PROP_EN_100FDX_CAP:
12818b11ca88SPaul Winder 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
12828b11ca88SPaul Winder 		mac_prop_info_set_default_uint8(prh,
1283*85e4aa97SDan McDonald 		    ((port->mlp_oper_proto & MLXCX_PROTO_100M) != 0 ||
1284*85e4aa97SDan McDonald 		    (port->mlp_ext_oper_proto & MLXCX_EXTPROTO_100M)) != 0);
12858b11ca88SPaul Winder 		break;
1286ebb7c6fdSAlex Wilson 	default:
1287ebb7c6fdSAlex Wilson 		break;
1288ebb7c6fdSAlex Wilson 	}
1289ebb7c6fdSAlex Wilson 
1290ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
1291ebb7c6fdSAlex Wilson }
1292ebb7c6fdSAlex Wilson 
1293ebb7c6fdSAlex Wilson static int
mlxcx_mac_setprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)1294ebb7c6fdSAlex Wilson mlxcx_mac_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1295ebb7c6fdSAlex Wilson     uint_t pr_valsize, const void *pr_val)
1296ebb7c6fdSAlex Wilson {
1297ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
1298ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = &mlxp->mlx_ports[0];
1299ebb7c6fdSAlex Wilson 	int ret = 0;
1300ebb7c6fdSAlex Wilson 	uint32_t new_mtu, new_hw_mtu, old_mtu;
1301ebb7c6fdSAlex Wilson 	mlxcx_buf_shard_t *sh;
1302ebb7c6fdSAlex Wilson 	boolean_t allocd = B_FALSE;
1303d77e6e0fSPaul Winder 	boolean_t relink = B_FALSE;
1304d77e6e0fSPaul Winder 	link_fec_t fec;
1305d77e6e0fSPaul Winder 	mlxcx_pplm_fec_caps_t cap_fec;
1306ebb7c6fdSAlex Wilson 
1307ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
1308ebb7c6fdSAlex Wilson 
1309ebb7c6fdSAlex Wilson 	switch (pr_num) {
1310ebb7c6fdSAlex Wilson 	case MAC_PROP_MTU:
1311ebb7c6fdSAlex Wilson 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
1312ebb7c6fdSAlex Wilson 		new_hw_mtu = new_mtu + MLXCX_MTU_OFFSET;
1313ebb7c6fdSAlex Wilson 		if (new_hw_mtu == port->mlp_mtu)
1314ebb7c6fdSAlex Wilson 			break;
1315ebb7c6fdSAlex Wilson 		if (new_hw_mtu > port->mlp_max_mtu) {
1316ebb7c6fdSAlex Wilson 			ret = EINVAL;
1317ebb7c6fdSAlex Wilson 			break;
1318ebb7c6fdSAlex Wilson 		}
1319ebb7c6fdSAlex Wilson 		sh = list_head(&mlxp->mlx_buf_shards);
1320ebb7c6fdSAlex Wilson 		for (; sh != NULL; sh = list_next(&mlxp->mlx_buf_shards, sh)) {
1321ebb7c6fdSAlex Wilson 			mutex_enter(&sh->mlbs_mtx);
1322ebb7c6fdSAlex Wilson 			if (!list_is_empty(&sh->mlbs_free) ||
132319325e87SPaul Winder 			    !list_is_empty(&sh->mlbs_busy) ||
132419325e87SPaul Winder 			    !list_is_empty(&sh->mlbs_loaned)) {
1325ebb7c6fdSAlex Wilson 				allocd = B_TRUE;
1326ebb7c6fdSAlex Wilson 				mutex_exit(&sh->mlbs_mtx);
1327ebb7c6fdSAlex Wilson 				break;
1328ebb7c6fdSAlex Wilson 			}
1329ebb7c6fdSAlex Wilson 			mutex_exit(&sh->mlbs_mtx);
1330ebb7c6fdSAlex Wilson 		}
1331ebb7c6fdSAlex Wilson 		if (allocd) {
1332ebb7c6fdSAlex Wilson 			ret = EBUSY;
1333ebb7c6fdSAlex Wilson 			break;
1334ebb7c6fdSAlex Wilson 		}
1335ebb7c6fdSAlex Wilson 		old_mtu = port->mlp_mtu;
1336ebb7c6fdSAlex Wilson 		ret = mac_maxsdu_update(mlxp->mlx_mac_hdl, new_mtu);
1337ebb7c6fdSAlex Wilson 		if (ret != 0)
1338ebb7c6fdSAlex Wilson 			break;
1339ebb7c6fdSAlex Wilson 		port->mlp_mtu = new_hw_mtu;
1340ebb7c6fdSAlex Wilson 		if (!mlxcx_cmd_modify_nic_vport_ctx(mlxp, port,
1341ebb7c6fdSAlex Wilson 		    MLXCX_MODIFY_NIC_VPORT_CTX_MTU)) {
1342ebb7c6fdSAlex Wilson 			port->mlp_mtu = old_mtu;
1343ebb7c6fdSAlex Wilson 			(void) mac_maxsdu_update(mlxp->mlx_mac_hdl, old_mtu);
1344ebb7c6fdSAlex Wilson 			ret = EIO;
1345ebb7c6fdSAlex Wilson 			break;
1346ebb7c6fdSAlex Wilson 		}
1347ebb7c6fdSAlex Wilson 		if (!mlxcx_cmd_set_port_mtu(mlxp, port)) {
1348ebb7c6fdSAlex Wilson 			port->mlp_mtu = old_mtu;
1349ebb7c6fdSAlex Wilson 			(void) mac_maxsdu_update(mlxp->mlx_mac_hdl, old_mtu);
1350ebb7c6fdSAlex Wilson 			ret = EIO;
1351ebb7c6fdSAlex Wilson 			break;
1352ebb7c6fdSAlex Wilson 		}
1353ebb7c6fdSAlex Wilson 		break;
1354d77e6e0fSPaul Winder 
1355d77e6e0fSPaul Winder 	case MAC_PROP_EN_FEC_CAP:
1356d77e6e0fSPaul Winder 		bcopy(pr_val, &fec, sizeof (fec));
1357d77e6e0fSPaul Winder 		if (!mlxcx_link_fec_cap(fec, &cap_fec)) {
1358d77e6e0fSPaul Winder 			ret = EINVAL;
1359d77e6e0fSPaul Winder 			break;
1360d77e6e0fSPaul Winder 		}
1361d77e6e0fSPaul Winder 
1362d77e6e0fSPaul Winder 		/*
1363d77e6e0fSPaul Winder 		 * Don't change the FEC if it is already at the requested
1364d77e6e0fSPaul Winder 		 * setting AND the port is up.
1365d77e6e0fSPaul Winder 		 * When the port is down, always set the FEC and attempt
1366d77e6e0fSPaul Winder 		 * to retrain the link.
1367d77e6e0fSPaul Winder 		 */
1368d77e6e0fSPaul Winder 		if (fec == port->mlp_fec_requested &&
1369d77e6e0fSPaul Winder 		    fec == mlxcx_fec_to_link_fec(port->mlp_fec_active) &&
1370d77e6e0fSPaul Winder 		    port->mlp_oper_status != MLXCX_PORT_STATUS_DOWN)
1371d77e6e0fSPaul Winder 			break;
1372d77e6e0fSPaul Winder 
1373d77e6e0fSPaul Winder 		/*
1374d77e6e0fSPaul Winder 		 * The most like cause of this failing is an invalid
1375d77e6e0fSPaul Winder 		 * or unsupported fec option.
1376d77e6e0fSPaul Winder 		 */
1377d77e6e0fSPaul Winder 		if (!mlxcx_cmd_modify_port_fec(mlxp, port, cap_fec)) {
1378d77e6e0fSPaul Winder 			ret = EINVAL;
1379d77e6e0fSPaul Winder 			break;
1380d77e6e0fSPaul Winder 		}
1381d77e6e0fSPaul Winder 
1382d77e6e0fSPaul Winder 		port->mlp_fec_requested = fec;
1383d77e6e0fSPaul Winder 
1384d77e6e0fSPaul Winder 		/*
1385d77e6e0fSPaul Winder 		 * For FEC to become effective, the link needs to go back
1386d77e6e0fSPaul Winder 		 * to training and negotiation state. This happens when
1387d77e6e0fSPaul Winder 		 * the link transitions from down to up, force a relink.
1388d77e6e0fSPaul Winder 		 */
1389d77e6e0fSPaul Winder 		relink = B_TRUE;
1390d77e6e0fSPaul Winder 		break;
1391d77e6e0fSPaul Winder 
1392ebb7c6fdSAlex Wilson 	default:
1393ebb7c6fdSAlex Wilson 		ret = ENOTSUP;
1394ebb7c6fdSAlex Wilson 		break;
1395ebb7c6fdSAlex Wilson 	}
1396ebb7c6fdSAlex Wilson 
1397d77e6e0fSPaul Winder 	if (relink) {
1398d77e6e0fSPaul Winder 		if (!mlxcx_cmd_modify_port_status(mlxp, port,
1399d77e6e0fSPaul Winder 		    MLXCX_PORT_STATUS_DOWN) ||
1400d77e6e0fSPaul Winder 		    !mlxcx_cmd_modify_port_status(mlxp, port,
1401d77e6e0fSPaul Winder 		    MLXCX_PORT_STATUS_UP)) {
1402d77e6e0fSPaul Winder 			ret = EIO;
1403d77e6e0fSPaul Winder 		}
1404d77e6e0fSPaul Winder 	}
1405ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
1406ebb7c6fdSAlex Wilson 
1407ebb7c6fdSAlex Wilson 	return (ret);
1408ebb7c6fdSAlex Wilson }
1409ebb7c6fdSAlex Wilson 
1410ebb7c6fdSAlex Wilson static int
mlxcx_mac_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)1411ebb7c6fdSAlex Wilson mlxcx_mac_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1412ebb7c6fdSAlex Wilson     uint_t pr_valsize, void *pr_val)
1413ebb7c6fdSAlex Wilson {
1414ebb7c6fdSAlex Wilson 	mlxcx_t *mlxp = (mlxcx_t *)arg;
1415ebb7c6fdSAlex Wilson 	mlxcx_port_t *port = &mlxp->mlx_ports[0];
1416ebb7c6fdSAlex Wilson 	uint64_t speed;
1417ebb7c6fdSAlex Wilson 	int ret = 0;
1418ebb7c6fdSAlex Wilson 
1419ebb7c6fdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
1420ebb7c6fdSAlex Wilson 
1421ebb7c6fdSAlex Wilson 	switch (pr_num) {
1422ebb7c6fdSAlex Wilson 	case MAC_PROP_DUPLEX:
1423ebb7c6fdSAlex Wilson 		if (pr_valsize < sizeof (link_duplex_t)) {
1424ebb7c6fdSAlex Wilson 			ret = EOVERFLOW;
1425ebb7c6fdSAlex Wilson 			break;
1426ebb7c6fdSAlex Wilson 		}
1427ebb7c6fdSAlex Wilson 		/* connectx parts only support full duplex */
1428ebb7c6fdSAlex Wilson 		*(link_duplex_t *)pr_val = LINK_DUPLEX_FULL;
1429ebb7c6fdSAlex Wilson 		break;
1430ebb7c6fdSAlex Wilson 	case MAC_PROP_SPEED:
1431ebb7c6fdSAlex Wilson 		if (pr_valsize < sizeof (uint64_t)) {
1432ebb7c6fdSAlex Wilson 			ret = EOVERFLOW;
1433ebb7c6fdSAlex Wilson 			break;
1434ebb7c6fdSAlex Wilson 		}
1435*85e4aa97SDan McDonald 		speed = mlxcx_speed_to_bits(port->mlp_oper_proto,
1436*85e4aa97SDan McDonald 		    port->mlp_ext_oper_proto);
1437ebb7c6fdSAlex Wilson 		bcopy(&speed, pr_val, sizeof (speed));
1438ebb7c6fdSAlex Wilson 		break;
1439ebb7c6fdSAlex Wilson 	case MAC_PROP_STATUS:
1440ebb7c6fdSAlex Wilson 		if (pr_valsize < sizeof (link_state_t)) {
1441ebb7c6fdSAlex Wilson 			ret = EOVERFLOW;
1442ebb7c6fdSAlex Wilson 			break;
1443ebb7c6fdSAlex Wilson 		}
1444ebb7c6fdSAlex Wilson 		switch (port->mlp_oper_status) {
1445ebb7c6fdSAlex Wilson 		case MLXCX_PORT_STATUS_UP:
1446ebb7c6fdSAlex Wilson 		case MLXCX_PORT_STATUS_UP_ONCE:
1447ebb7c6fdSAlex Wilson 			*(link_state_t *)pr_val = LINK_STATE_UP;
1448ebb7c6fdSAlex Wilson 			break;
1449ebb7c6fdSAlex Wilson 		case MLXCX_PORT_STATUS_DOWN:
1450ebb7c6fdSAlex Wilson 			*(link_state_t *)pr_val = LINK_STATE_DOWN;
1451ebb7c6fdSAlex Wilson 			break;
1452ebb7c6fdSAlex Wilson 		default:
1453ebb7c6fdSAlex Wilson 			*(link_state_t *)pr_val = LINK_STATE_UNKNOWN;
1454ebb7c6fdSAlex Wilson 		}
1455ebb7c6fdSAlex Wilson 		break;
1456ebb7c6fdSAlex Wilson 	case MAC_PROP_AUTONEG:
1457ebb7c6fdSAlex Wilson 		if (pr_valsize < sizeof (uint8_t)) {
1458ebb7c6fdSAlex Wilson 			ret = EOVERFLOW;
1459ebb7c6fdSAlex Wilson 			break;
1460ebb7c6fdSAlex Wilson 		}
1461ebb7c6fdSAlex Wilson 		*(uint8_t *)pr_val = port->mlp_autoneg;
1462ebb7c6fdSAlex Wilson 		break;
1463d77e6e0fSPaul Winder 	case MAC_PROP_ADV_FEC_CAP:
1464d77e6e0fSPaul Winder 		if (pr_valsize < sizeof (link_fec_t)) {
1465d77e6e0fSPaul Winder 			ret = EOVERFLOW;
1466d77e6e0fSPaul Winder 			break;
1467d77e6e0fSPaul Winder 		}
1468d77e6e0fSPaul Winder 		*(link_fec_t *)pr_val =
1469d77e6e0fSPaul Winder 		    mlxcx_fec_to_link_fec(port->mlp_fec_active);
1470d77e6e0fSPaul Winder 		break;
1471d77e6e0fSPaul Winder 	case MAC_PROP_EN_FEC_CAP:
1472d77e6e0fSPaul Winder 		if (pr_valsize < sizeof (link_fec_t)) {
1473d77e6e0fSPaul Winder 			ret = EOVERFLOW;
1474d77e6e0fSPaul Winder 			break;
1475d77e6e0fSPaul Winder 		}
1476d77e6e0fSPaul Winder 		*(link_fec_t *)pr_val = port->mlp_fec_requested;
1477d77e6e0fSPaul Winder 		break;
1478ebb7c6fdSAlex Wilson 	case MAC_PROP_MTU:
1479ebb7c6fdSAlex Wilson 		if (pr_valsize < sizeof (uint32_t)) {
1480ebb7c6fdSAlex Wilson 			ret = EOVERFLOW;
1481ebb7c6fdSAlex Wilson 			break;
1482ebb7c6fdSAlex Wilson 		}
1483ebb7c6fdSAlex Wilson 		*(uint32_t *)pr_val = port->mlp_mtu - MLXCX_MTU_OFFSET;
1484ebb7c6fdSAlex Wilson 		break;
1485*85e4aa97SDan McDonald 	case MAC_PROP_ADV_400GFDX_CAP:
1486*85e4aa97SDan McDonald 	case MAC_PROP_EN_400GFDX_CAP:
1487*85e4aa97SDan McDonald 		if (pr_valsize < sizeof (uint8_t)) {
1488*85e4aa97SDan McDonald 			ret = EOVERFLOW;
1489*85e4aa97SDan McDonald 			break;
1490*85e4aa97SDan McDonald 		}
1491*85e4aa97SDan McDonald 		*(uint8_t *)pr_val =
1492*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_400G) != 0;
1493*85e4aa97SDan McDonald 		break;
1494*85e4aa97SDan McDonald 	case MAC_PROP_ADV_200GFDX_CAP:
1495*85e4aa97SDan McDonald 	case MAC_PROP_EN_200GFDX_CAP:
1496*85e4aa97SDan McDonald 		if (pr_valsize < sizeof (uint8_t)) {
1497*85e4aa97SDan McDonald 			ret = EOVERFLOW;
1498*85e4aa97SDan McDonald 			break;
1499*85e4aa97SDan McDonald 		}
1500*85e4aa97SDan McDonald 		*(uint8_t *)pr_val =
1501*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_200G) != 0;
1502*85e4aa97SDan McDonald 		break;
15038b11ca88SPaul Winder 	case MAC_PROP_ADV_100GFDX_CAP:
15048b11ca88SPaul Winder 	case MAC_PROP_EN_100GFDX_CAP:
15058b11ca88SPaul Winder 		if (pr_valsize < sizeof (uint8_t)) {
15068b11ca88SPaul Winder 			ret = EOVERFLOW;
15078b11ca88SPaul Winder 			break;
15088b11ca88SPaul Winder 		}
15098b11ca88SPaul Winder 		*(uint8_t *)pr_val = (port->mlp_max_proto &
1510*85e4aa97SDan McDonald 		    MLXCX_PROTO_100G) != 0 ||
1511*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_100G) != 0;
15128b11ca88SPaul Winder 		break;
15138b11ca88SPaul Winder 	case MAC_PROP_ADV_50GFDX_CAP:
15148b11ca88SPaul Winder 	case MAC_PROP_EN_50GFDX_CAP:
15158b11ca88SPaul Winder 		if (pr_valsize < sizeof (uint8_t)) {
15168b11ca88SPaul Winder 			ret = EOVERFLOW;
15178b11ca88SPaul Winder 			break;
15188b11ca88SPaul Winder 		}
15198b11ca88SPaul Winder 		*(uint8_t *)pr_val = (port->mlp_max_proto &
1520*85e4aa97SDan McDonald 		    MLXCX_PROTO_50G) != 0 ||
1521*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_50G) != 0;
15228b11ca88SPaul Winder 		break;
15238b11ca88SPaul Winder 	case MAC_PROP_ADV_40GFDX_CAP:
15248b11ca88SPaul Winder 	case MAC_PROP_EN_40GFDX_CAP:
15258b11ca88SPaul Winder 		if (pr_valsize < sizeof (uint8_t)) {
15268b11ca88SPaul Winder 			ret = EOVERFLOW;
15278b11ca88SPaul Winder 			break;
15288b11ca88SPaul Winder 		}
15298b11ca88SPaul Winder 		*(uint8_t *)pr_val = (port->mlp_max_proto &
1530*85e4aa97SDan McDonald 		    MLXCX_PROTO_40G) != 0 ||
1531*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_40G) != 0;
15328b11ca88SPaul Winder 		break;
15338b11ca88SPaul Winder 	case MAC_PROP_ADV_25GFDX_CAP:
15348b11ca88SPaul Winder 	case MAC_PROP_EN_25GFDX_CAP:
15358b11ca88SPaul Winder 		if (pr_valsize < sizeof (uint8_t)) {
15368b11ca88SPaul Winder 			ret = EOVERFLOW;
15378b11ca88SPaul Winder 			break;
15388b11ca88SPaul Winder 		}
15398b11ca88SPaul Winder 		*(uint8_t *)pr_val = (port->mlp_max_proto &
1540*85e4aa97SDan McDonald 		    MLXCX_PROTO_25G) != 0 ||
1541*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_25G) != 0;
15428b11ca88SPaul Winder 		break;
15438b11ca88SPaul Winder 	case MAC_PROP_ADV_10GFDX_CAP:
15448b11ca88SPaul Winder 	case MAC_PROP_EN_10GFDX_CAP:
15458b11ca88SPaul Winder 		if (pr_valsize < sizeof (uint8_t)) {
15468b11ca88SPaul Winder 			ret = EOVERFLOW;
15478b11ca88SPaul Winder 			break;
15488b11ca88SPaul Winder 		}
15498b11ca88SPaul Winder 		*(uint8_t *)pr_val = (port->mlp_max_proto &
1550*85e4aa97SDan McDonald 		    MLXCX_PROTO_10G) != 0 ||
1551*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_10G) != 0;
15528b11ca88SPaul Winder 		break;
15538b11ca88SPaul Winder 	case MAC_PROP_ADV_1000FDX_CAP:
15548b11ca88SPaul Winder 	case MAC_PROP_EN_1000FDX_CAP:
15558b11ca88SPaul Winder 		if (pr_valsize < sizeof (uint8_t)) {
15568b11ca88SPaul Winder 			ret = EOVERFLOW;
15578b11ca88SPaul Winder 			break;
15588b11ca88SPaul Winder 		}
15598b11ca88SPaul Winder 		*(uint8_t *)pr_val = (port->mlp_max_proto &
1560*85e4aa97SDan McDonald 		    MLXCX_PROTO_1G) != 0 ||
1561*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_1G) != 0;
15628b11ca88SPaul Winder 		break;
15638b11ca88SPaul Winder 	case MAC_PROP_ADV_100FDX_CAP:
15648b11ca88SPaul Winder 	case MAC_PROP_EN_100FDX_CAP:
15658b11ca88SPaul Winder 		if (pr_valsize < sizeof (uint8_t)) {
15668b11ca88SPaul Winder 			ret = EOVERFLOW;
15678b11ca88SPaul Winder 			break;
15688b11ca88SPaul Winder 		}
15698b11ca88SPaul Winder 		*(uint8_t *)pr_val = (port->mlp_max_proto &
1570*85e4aa97SDan McDonald 		    MLXCX_PROTO_100M) != 0 ||
1571*85e4aa97SDan McDonald 		    (port->mlp_ext_max_proto & MLXCX_EXTPROTO_100M) != 0;
15728b11ca88SPaul Winder 		break;
1573ebb7c6fdSAlex Wilson 	default:
1574ebb7c6fdSAlex Wilson 		ret = ENOTSUP;
1575ebb7c6fdSAlex Wilson 		break;
1576ebb7c6fdSAlex Wilson 	}
1577ebb7c6fdSAlex Wilson 
1578ebb7c6fdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
1579ebb7c6fdSAlex Wilson 
1580ebb7c6fdSAlex Wilson 	return (ret);
1581ebb7c6fdSAlex Wilson }
1582ebb7c6fdSAlex Wilson 
1583ebb7c6fdSAlex Wilson #define	MLXCX_MAC_CALLBACK_FLAGS \
1584ebb7c6fdSAlex Wilson 	(MC_GETCAPAB | MC_GETPROP | MC_PROPINFO | MC_SETPROP)
1585ebb7c6fdSAlex Wilson 
1586ebb7c6fdSAlex Wilson static mac_callbacks_t mlxcx_mac_callbacks = {
1587ebb7c6fdSAlex Wilson 	.mc_callbacks = MLXCX_MAC_CALLBACK_FLAGS,
1588ebb7c6fdSAlex Wilson 	.mc_getstat = mlxcx_mac_stat,
1589ebb7c6fdSAlex Wilson 	.mc_start = mlxcx_mac_start,
1590ebb7c6fdSAlex Wilson 	.mc_stop = mlxcx_mac_stop,
1591ebb7c6fdSAlex Wilson 	.mc_setpromisc = mlxcx_mac_setpromisc,
1592ebb7c6fdSAlex Wilson 	.mc_multicst = mlxcx_mac_multicast,
1593ebb7c6fdSAlex Wilson 	.mc_ioctl = NULL,
1594ebb7c6fdSAlex Wilson 	.mc_getcapab = mlxcx_mac_getcapab,
1595ebb7c6fdSAlex Wilson 	.mc_setprop = mlxcx_mac_setprop,
1596ebb7c6fdSAlex Wilson 	.mc_getprop = mlxcx_mac_getprop,
1597ebb7c6fdSAlex Wilson 	.mc_propinfo = mlxcx_mac_propinfo,
1598ebb7c6fdSAlex Wilson 	.mc_tx = NULL,
1599ebb7c6fdSAlex Wilson 	.mc_unicst = NULL,
1600ebb7c6fdSAlex Wilson };
1601ebb7c6fdSAlex Wilson 
1602ebb7c6fdSAlex Wilson boolean_t
mlxcx_register_mac(mlxcx_t * mlxp)1603ebb7c6fdSAlex Wilson mlxcx_register_mac(mlxcx_t *mlxp)
1604ebb7c6fdSAlex Wilson {
1605ebb7c6fdSAlex Wilson 	mac_register_t *mac = mac_alloc(MAC_VERSION);
1606ebb7c6fdSAlex Wilson 	mlxcx_port_t *port;
1607ebb7c6fdSAlex Wilson 	int ret;
1608ebb7c6fdSAlex Wilson 
1609ebb7c6fdSAlex Wilson 	if (mac == NULL)
1610ebb7c6fdSAlex Wilson 		return (B_FALSE);
1611ebb7c6fdSAlex Wilson 
1612ebb7c6fdSAlex Wilson 	VERIFY3U(mlxp->mlx_nports, ==, 1);
1613ebb7c6fdSAlex Wilson 	port = &mlxp->mlx_ports[0];
1614ebb7c6fdSAlex Wilson 
161580d1a7bdSAlex Wilson 	mutex_enter(&port->mlp_mtx);
161680d1a7bdSAlex Wilson 
1617ebb7c6fdSAlex Wilson 	mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1618ebb7c6fdSAlex Wilson 	mac->m_driver = mlxp;
1619ebb7c6fdSAlex Wilson 	mac->m_dip = mlxp->mlx_dip;
1620ebb7c6fdSAlex Wilson 	mac->m_src_addr = port->mlp_mac_address;
1621ebb7c6fdSAlex Wilson 	mac->m_callbacks = &mlxcx_mac_callbacks;
1622ebb7c6fdSAlex Wilson 	mac->m_min_sdu = MLXCX_MTU_OFFSET;
1623ebb7c6fdSAlex Wilson 	mac->m_max_sdu = port->mlp_mtu - MLXCX_MTU_OFFSET;
1624ebb7c6fdSAlex Wilson 	mac->m_margin = VLAN_TAGSZ;
1625ebb7c6fdSAlex Wilson 	mac->m_priv_props = mlxcx_priv_props;
1626ebb7c6fdSAlex Wilson 	mac->m_v12n = MAC_VIRT_LEVEL1;
1627ebb7c6fdSAlex Wilson 
1628ebb7c6fdSAlex Wilson 	ret = mac_register(mac, &mlxp->mlx_mac_hdl);
1629ebb7c6fdSAlex Wilson 	if (ret != 0) {
1630ebb7c6fdSAlex Wilson 		mlxcx_warn(mlxp, "mac_register() returned %d", ret);
1631ebb7c6fdSAlex Wilson 	}
1632ebb7c6fdSAlex Wilson 	mac_free(mac);
1633ebb7c6fdSAlex Wilson 
163480d1a7bdSAlex Wilson 	mutex_exit(&port->mlp_mtx);
163580d1a7bdSAlex Wilson 
1636ebb7c6fdSAlex Wilson 	mlxcx_update_link_state(mlxp, port);
1637ebb7c6fdSAlex Wilson 
1638ebb7c6fdSAlex Wilson 	return (ret == 0);
1639ebb7c6fdSAlex Wilson }
1640