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