xref: /illumos-gate/usr/src/uts/common/io/cxgbe/t4nex/t4_mac.c (revision f3682895b2a97c009685f16e8a4e5d3dc80e11f2)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source. A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * This file is part of the Chelsio T4 support code.
14  *
15  * Copyright (C) 2010-2013 Chelsio Communications.  All rights reserved.
16  *
17  * This program is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the LICENSE file included in this
20  * release for licensing terms and conditions.
21  */
22 
23 /*
24  * Copyright 2020 RackTop Systems, Inc.
25  * Copyright 2021 Oxide Computer Company
26  */
27 
28 #include <sys/ddi.h>
29 #include <sys/sunddi.h>
30 #include <sys/dlpi.h>
31 #include <sys/mac_provider.h>
32 #include <sys/mac_ether.h>
33 #include <sys/strsubr.h>
34 #include <sys/queue.h>
35 
36 #include "common/common.h"
37 #include "common/t4_regs.h"
38 
39 static int t4_mc_getstat(void *arg, uint_t stat, uint64_t *val);
40 static int t4_mc_start(void *arg);
41 static void t4_mc_stop(void *arg);
42 static int t4_mc_setpromisc(void *arg, boolean_t on);
43 static int t4_mc_multicst(void *arg, boolean_t add, const uint8_t *mcaddr);
44 static int t4_mc_unicst(void *arg, const uint8_t *ucaddr);
45 static boolean_t t4_mc_getcapab(void *arg, mac_capab_t cap, void *data);
46 static int t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id,
47     uint_t size, const void *val);
48 static int t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id,
49     uint_t size, void *val);
50 static void t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id,
51     mac_prop_info_handle_t ph);
52 
53 static int t4_init_synchronized(struct port_info *pi);
54 static int t4_uninit_synchronized(struct port_info *pi);
55 static void propinfo(struct port_info *pi, const char *name,
56     mac_prop_info_handle_t ph);
57 static int getprop(struct port_info *pi, const char *name, uint_t size,
58     void *val);
59 static int setprop(struct port_info *pi, const char *name, const void *val);
60 
61 mac_callbacks_t t4_m_callbacks = {
62 	.mc_callbacks	= MC_GETCAPAB | MC_PROPERTIES,
63 	.mc_getstat	= t4_mc_getstat,
64 	.mc_start	= t4_mc_start,
65 	.mc_stop	= t4_mc_stop,
66 	.mc_setpromisc	= t4_mc_setpromisc,
67 	.mc_multicst	= t4_mc_multicst,
68 	.mc_unicst =    t4_mc_unicst,
69 	.mc_tx =        t4_mc_tx,
70 	.mc_getcapab =	t4_mc_getcapab,
71 	.mc_setprop =	t4_mc_setprop,
72 	.mc_getprop =	t4_mc_getprop,
73 	.mc_propinfo =	t4_mc_propinfo,
74 };
75 
76 /* I couldn't comeup with a better idea of not redefine
77  * another strcture and instead somehow reuse the earlier
78  * above structure and modify its members.
79  */
80 mac_callbacks_t t4_m_ring_callbacks = {
81 	.mc_callbacks =	MC_GETCAPAB | MC_PROPERTIES,
82 	.mc_getstat =	t4_mc_getstat,
83 	.mc_start =	t4_mc_start,
84 	.mc_stop =	t4_mc_stop,
85 	.mc_setpromisc =t4_mc_setpromisc,
86 	.mc_multicst =	t4_mc_multicst,
87 	.mc_unicst =    NULL, /* t4_addmac */
88 	.mc_tx =        NULL, /* t4_eth_tx */
89 	.mc_getcapab	= t4_mc_getcapab,
90 	.mc_setprop	= t4_mc_setprop,
91 	.mc_getprop	= t4_mc_getprop,
92 	.mc_propinfo	= t4_mc_propinfo,
93 };
94 
95 #define	T4PROP_TMR_IDX "_holdoff_timer_idx"
96 #define	T4PROP_PKTC_IDX "_holdoff_pktc_idx"
97 #define	T4PROP_MTU "_mtu"
98 #define	T4PROP_HW_CSUM	"_hw_csum"
99 #define	T4PROP_HW_LSO	"_hw_lso"
100 #define	T4PROP_TX_PAUSE	"_tx_pause"
101 #define	T4PROP_RX_PAUSE	"_rx_pause"
102 
103 char *t4_priv_props[] = {
104 	T4PROP_TMR_IDX,
105 	T4PROP_PKTC_IDX,
106 #if MAC_VERSION == 1
107 	/* MAC_VERSION 1 doesn't seem to use MAC_PROP_MTU, hmmmm */
108 	T4PROP_MTU,
109 #endif
110 	T4PROP_HW_CSUM,
111 	T4PROP_HW_LSO,
112 	T4PROP_TX_PAUSE,
113 	T4PROP_RX_PAUSE,
114 	NULL
115 };
116 
117 static int
118 t4_mc_getstat(void *arg, uint_t stat, uint64_t *val)
119 {
120 	struct port_info *pi = arg;
121 	struct adapter *sc = pi->adapter;
122 	struct link_config *lc = &pi->link_cfg;
123 
124 #define	GET_STAT(name) \
125 	t4_read_reg64(sc, PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_##name##_L))
126 
127 	switch (stat) {
128 	case MAC_STAT_IFSPEED:
129 		if (lc->link_ok != 0) {
130 			*val = lc->speed;
131 			*val *= 1000000;
132 		} else
133 			*val = 0;
134 		break;
135 
136 	case MAC_STAT_MULTIRCV:
137 		*val = GET_STAT(RX_PORT_MCAST);
138 		break;
139 
140 	case MAC_STAT_BRDCSTRCV:
141 		*val = GET_STAT(RX_PORT_BCAST);
142 		break;
143 
144 	case MAC_STAT_MULTIXMT:
145 		*val = GET_STAT(TX_PORT_MCAST);
146 		break;
147 
148 	case MAC_STAT_BRDCSTXMT:
149 		*val = GET_STAT(TX_PORT_BCAST);
150 		break;
151 
152 	case MAC_STAT_NORCVBUF:
153 		*val = 0;	/* TODO should come from rxq->nomem */
154 		break;
155 
156 	case MAC_STAT_IERRORS:
157 		*val = GET_STAT(RX_PORT_MTU_ERROR) +
158 		    GET_STAT(RX_PORT_MTU_CRC_ERROR) +
159 		    GET_STAT(RX_PORT_CRC_ERROR) +
160 		    GET_STAT(RX_PORT_LEN_ERROR) +
161 		    GET_STAT(RX_PORT_SYM_ERROR) +
162 		    GET_STAT(RX_PORT_LESS_64B);
163 		break;
164 
165 	case MAC_STAT_UNKNOWNS:
166 		return (ENOTSUP);
167 
168 	case MAC_STAT_NOXMTBUF:
169 		*val = GET_STAT(TX_PORT_DROP);
170 		break;
171 
172 	case MAC_STAT_OERRORS:
173 		*val = GET_STAT(TX_PORT_ERROR);
174 		break;
175 
176 	case MAC_STAT_COLLISIONS:
177 		return (ENOTSUP);
178 
179 	case MAC_STAT_RBYTES:
180 		*val = GET_STAT(RX_PORT_BYTES);
181 		break;
182 
183 	case MAC_STAT_IPACKETS:
184 		*val = GET_STAT(RX_PORT_FRAMES);
185 		break;
186 
187 	case MAC_STAT_OBYTES:
188 		*val = GET_STAT(TX_PORT_BYTES);
189 		break;
190 
191 	case MAC_STAT_OPACKETS:
192 		*val = GET_STAT(TX_PORT_FRAMES);
193 		break;
194 
195 	case ETHER_STAT_ALIGN_ERRORS:
196 		return (ENOTSUP);
197 
198 	case ETHER_STAT_FCS_ERRORS:
199 		*val = GET_STAT(RX_PORT_CRC_ERROR);
200 		break;
201 
202 	case ETHER_STAT_FIRST_COLLISIONS:
203 	case ETHER_STAT_MULTI_COLLISIONS:
204 	case ETHER_STAT_SQE_ERRORS:
205 	case ETHER_STAT_DEFER_XMTS:
206 	case ETHER_STAT_TX_LATE_COLLISIONS:
207 	case ETHER_STAT_EX_COLLISIONS:
208 		return (ENOTSUP);
209 
210 	case ETHER_STAT_MACXMT_ERRORS:
211 		*val = GET_STAT(TX_PORT_ERROR);
212 		break;
213 
214 	case ETHER_STAT_CARRIER_ERRORS:
215 		return (ENOTSUP);
216 
217 	case ETHER_STAT_TOOLONG_ERRORS:
218 		*val = GET_STAT(RX_PORT_MTU_ERROR);
219 		break;
220 
221 	case ETHER_STAT_MACRCV_ERRORS:
222 		*val = GET_STAT(RX_PORT_MTU_ERROR) +
223 		    GET_STAT(RX_PORT_MTU_CRC_ERROR) +
224 		    GET_STAT(RX_PORT_CRC_ERROR) +
225 		    GET_STAT(RX_PORT_LEN_ERROR) +
226 		    GET_STAT(RX_PORT_SYM_ERROR) +
227 		    GET_STAT(RX_PORT_LESS_64B);
228 		break;
229 
230 	case ETHER_STAT_XCVR_ADDR:
231 	case ETHER_STAT_XCVR_ID:
232 	case ETHER_STAT_XCVR_INUSE:
233 		return (ENOTSUP);
234 
235 	case ETHER_STAT_CAP_100GFDX:
236 		*val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_100G);
237 		break;
238 
239 	case ETHER_STAT_CAP_40GFDX:
240 		*val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_40G);
241 		break;
242 
243 	case ETHER_STAT_CAP_25GFDX:
244 		*val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_25G);
245 		break;
246 
247 	case ETHER_STAT_CAP_10GFDX:
248 		*val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_10G);
249 		break;
250 
251 	case ETHER_STAT_CAP_1000FDX:
252 		*val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_1G);
253 		break;
254 
255 	case ETHER_STAT_CAP_1000HDX:
256 		return (ENOTSUP);
257 
258 	case ETHER_STAT_CAP_100FDX:
259 		*val = !!(lc->pcaps & FW_PORT_CAP32_SPEED_100M);
260 		break;
261 
262 	case ETHER_STAT_CAP_100HDX:
263 		return (ENOTSUP);
264 
265 	case ETHER_STAT_CAP_10FDX:
266 	case ETHER_STAT_CAP_10HDX:
267 		return (ENOTSUP);
268 
269 	case ETHER_STAT_CAP_ASMPAUSE:
270 		*val = 0;
271 		break;
272 
273 	case ETHER_STAT_CAP_PAUSE:
274 		*val = 1;
275 		break;
276 
277 	case ETHER_STAT_CAP_AUTONEG:
278 		*val = !!(lc->pcaps & FW_PORT_CAP32_ANEG);
279 		break;
280 
281 	/*
282 	 * We have set flow control configuration based on tx_pause and rx_pause
283 	 * values supported through ndd. Now, we need to translate the settings
284 	 * we have in link_config structure to adv_cap_asmpause and
285 	 * adv_cap_pause.
286 	 *
287 	 * There are 4 combinations possible and the translation is as below:
288 	 * tx_pause = 0 => We don't send pause frames during Rx congestion
289 	 * tx_pause = 1 => We send pause frames during Rx congestion
290 	 * rx_pause = 0 => We ignore received pause frames
291 	 * rx_pause = 1 => We pause transmission when we receive pause frames
292 	 *
293 	 * +----------------------------+----------------------------------+
294 	 * |  tx_pause	|    rx_pause	| adv_cap_asmpause | adv_cap_pause |
295 	 * +-------------------------+-------------------------------------+
296 	 * |	0	|	0	|	0	   |	0	   |
297 	 * |	0	|	1	|	1	   |	0	   |
298 	 * |	1	|	0	|	1	   |	1	   |
299 	 * |	1	|	1	|	0	   |	1	   |
300 	 * +----------------------------+----------------------------------+
301 	 */
302 
303 	/* Advertised asymmetric pause capability */
304 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
305 		*val = (((lc->requested_fc & PAUSE_TX) ? 1 : 0) ^
306 		    (lc->requested_fc & PAUSE_RX));
307 		break;
308 
309 	/* Advertised pause capability */
310 	case ETHER_STAT_ADV_CAP_PAUSE:
311 		*val = (lc->requested_fc & PAUSE_TX) ? 1 : 0;
312 		break;
313 
314 	case ETHER_STAT_ADV_CAP_100GFDX:
315 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_100G);
316 		break;
317 
318 	case ETHER_STAT_ADV_CAP_40GFDX:
319 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_40G);
320 		break;
321 
322 	case ETHER_STAT_ADV_CAP_25GFDX:
323 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_25G);
324 		break;
325 
326 	case ETHER_STAT_ADV_CAP_10GFDX:
327 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_10G);
328 		break;
329 
330 	case ETHER_STAT_ADV_CAP_1000FDX:
331 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_1G);
332 		break;
333 
334 	case ETHER_STAT_ADV_CAP_AUTONEG:
335 		*val = !!(lc->acaps & FW_PORT_CAP32_ANEG);
336 		break;
337 
338 	case ETHER_STAT_ADV_CAP_1000HDX:
339 	case ETHER_STAT_ADV_CAP_100FDX:
340 	case ETHER_STAT_ADV_CAP_100HDX:
341 	case ETHER_STAT_ADV_CAP_10FDX:
342 	case ETHER_STAT_ADV_CAP_10HDX:
343 		return (ENOTSUP);	/* TODO */
344 
345 
346 	case ETHER_STAT_LP_CAP_100GFDX:
347 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_100G);
348 		break;
349 
350 	case ETHER_STAT_LP_CAP_40GFDX:
351 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_40G);
352 		break;
353 
354 	case ETHER_STAT_LP_CAP_25GFDX:
355 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_25G);
356 		break;
357 
358 	case ETHER_STAT_LP_CAP_10GFDX:
359 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_10G);
360 		break;
361 
362 	case ETHER_STAT_LP_CAP_1000FDX:
363 		*val = !!(lc->acaps & FW_PORT_CAP32_SPEED_1G);
364 		break;
365 
366 	case ETHER_STAT_LP_CAP_AUTONEG:
367 		*val = !!(lc->acaps & FW_PORT_CAP32_ANEG);
368 		break;
369 
370 	case ETHER_STAT_LP_CAP_1000HDX:
371 	case ETHER_STAT_LP_CAP_100FDX:
372 	case ETHER_STAT_LP_CAP_100HDX:
373 	case ETHER_STAT_LP_CAP_10FDX:
374 	case ETHER_STAT_LP_CAP_10HDX:
375 	case ETHER_STAT_LP_CAP_ASMPAUSE:
376 	case ETHER_STAT_LP_CAP_PAUSE:
377 		return (ENOTSUP);
378 
379 	case ETHER_STAT_LINK_ASMPAUSE:
380 		*val = 0;
381 		break;
382 
383 	case ETHER_STAT_LINK_PAUSE:
384 		*val = 1;
385 		break;
386 
387 	case ETHER_STAT_LINK_AUTONEG:
388 		*val = lc->autoneg == AUTONEG_ENABLE;
389 		break;
390 
391 	case ETHER_STAT_LINK_DUPLEX:
392 		if (lc->link_ok != 0)
393 			*val = LINK_DUPLEX_FULL;
394 		else
395 			*val = LINK_DUPLEX_UNKNOWN;
396 		break;
397 
398 	default:
399 #ifdef DEBUG
400 		cxgb_printf(pi->dip, CE_NOTE, "stat %d not implemented.", stat);
401 #endif
402 		return (ENOTSUP);
403 	}
404 #undef GET_STAT
405 
406 	return (0);
407 }
408 
409 static int
410 t4_mc_start(void *arg)
411 {
412 	struct port_info *pi = arg;
413 	int rc;
414 
415 	rc = begin_synchronized_op(pi, 0, 1);
416 	if (rc != 0)
417 		return (rc);
418 	rc = t4_init_synchronized(pi);
419 	end_synchronized_op(pi, 0);
420 
421 	return (rc);
422 }
423 
424 static void
425 t4_mc_stop(void *arg)
426 {
427 	struct port_info *pi = arg;
428 
429 	while (begin_synchronized_op(pi, 0, 1) != 0)
430 		continue;
431 	(void) t4_uninit_synchronized(pi);
432 	end_synchronized_op(pi, 0);
433 }
434 
435 static int
436 t4_mc_setpromisc(void *arg, boolean_t on)
437 {
438 	struct port_info *pi = arg;
439 	struct adapter *sc = pi->adapter;
440 	int rc;
441 
442 	rc = begin_synchronized_op(pi, 1, 1);
443 	if (rc != 0)
444 		return (rc);
445 	rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, -1, on ? 1 : 0, -1, -1, -1,
446 	    false);
447 	end_synchronized_op(pi, 1);
448 
449 	return (rc);
450 }
451 
452 /*
453  * TODO: Starts failing as soon as the 336 entry table fills up.  Need to use
454  * hash in that case.
455  */
456 static int
457 t4_mc_multicst(void *arg, boolean_t add, const uint8_t *mcaddr)
458 {
459 	struct port_info *pi = arg;
460 	struct adapter *sc = pi->adapter;
461 	struct fw_vi_mac_cmd c;
462 	int len16, rc;
463 
464 	len16 = howmany(sizeof (c.op_to_viid) + sizeof (c.freemacs_to_len16) +
465 	    sizeof (c.u.exact[0]), 16);
466 	c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST |
467 	    F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(pi->viid));
468 	c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(len16));
469 	c.u.exact[0].valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID |
470 	    V_FW_VI_MAC_CMD_IDX(add ? FW_VI_MAC_ADD_MAC :
471 	    FW_VI_MAC_MAC_BASED_FREE));
472 	bcopy(mcaddr, &c.u.exact[0].macaddr, ETHERADDRL);
473 
474 	rc = begin_synchronized_op(pi, 1, 1);
475 	if (rc != 0)
476 		return (rc);
477 	rc = -t4_wr_mbox_meat(sc, sc->mbox, &c, len16 * 16, &c, true);
478 	end_synchronized_op(pi, 1);
479 	if (rc != 0)
480 		return (rc);
481 #ifdef DEBUG
482 	/*
483 	 * TODO: Firmware doesn't seem to return the correct index on removal
484 	 * (it gives back 0x3fd FW_VI_MAC_MAC_BASED_FREE unchanged. Remove this
485 	 * code once it is fixed.
486 	 */
487 	else {
488 		uint16_t idx;
489 
490 		idx = G_FW_VI_MAC_CMD_IDX(ntohs(c.u.exact[0].valid_to_idx));
491 		cxgb_printf(pi->dip, CE_NOTE,
492 		    "%02x:%02x:%02x:%02x:%02x:%02x %s %d", mcaddr[0],
493 		    mcaddr[1], mcaddr[2], mcaddr[3], mcaddr[4], mcaddr[5],
494 		    add ? "added at index" : "removed from index", idx);
495 	}
496 #endif
497 
498 	return (0);
499 }
500 
501 int
502 t4_mc_unicst(void *arg, const uint8_t *ucaddr)
503 {
504 	struct port_info *pi = arg;
505 	struct adapter *sc = pi->adapter;
506 	int rc;
507 
508 	if (ucaddr == NULL)
509 		return (EINVAL);
510 
511 	rc = begin_synchronized_op(pi, 1, 1);
512 	if (rc != 0)
513 		return (rc);
514 
515 	/* We will support adding only one mac address */
516 	if (pi->adapter->props.multi_rings && pi->macaddr_cnt) {
517 		end_synchronized_op(pi, 1);
518 		return (ENOSPC);
519 	}
520 	rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, ucaddr,
521 			   true, &pi->smt_idx);
522 	if (rc < 0)
523 		rc = -rc;
524 	else {
525 		pi->macaddr_cnt++;
526 		pi->xact_addr_filt = rc;
527 		rc = 0;
528 	}
529 	end_synchronized_op(pi, 1);
530 
531 	return (rc);
532 }
533 
534 int
535 t4_addmac(void *arg, const uint8_t *ucaddr)
536 {
537 	return (t4_mc_unicst(arg, ucaddr));
538 }
539 
540 static int
541 t4_remmac(void *arg, const uint8_t *mac_addr)
542 {
543 	struct port_info *pi = arg;
544 	int rc;
545 
546 	rc = begin_synchronized_op(pi, 1, 1);
547 	if (rc != 0)
548 		return (rc);
549 
550 	pi->macaddr_cnt--;
551 	end_synchronized_op(pi, 1);
552 
553 	return (0);
554 }
555 
556 /*
557  * Callback funtion for MAC layer to register all groups.
558  */
559 void
560 t4_fill_group(void *arg, mac_ring_type_t rtype, const int rg_index,
561 	      mac_group_info_t *infop, mac_group_handle_t gh)
562 {
563 	struct port_info *pi = arg;
564 
565 	switch (rtype) {
566 	case MAC_RING_TYPE_RX: {
567 		infop->mgi_driver = (mac_group_driver_t)arg;
568 		infop->mgi_start = NULL;
569 		infop->mgi_stop = NULL;
570 		infop->mgi_addmac = t4_addmac;
571 		infop->mgi_remmac = t4_remmac;
572 		infop->mgi_count = pi->nrxq;
573 		break;
574 	}
575 	case MAC_RING_TYPE_TX:
576 	default:
577 		ASSERT(0);
578 		break;
579 	}
580 }
581 
582 static int
583 t4_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
584 {
585 	struct sge_rxq *rxq = (struct sge_rxq *)rh;
586 
587 	RXQ_LOCK(rxq);
588 	rxq->ring_gen_num = mr_gen_num;
589 	RXQ_UNLOCK(rxq);
590 	return (0);
591 }
592 
593 /*
594  * Enable interrupt on the specificed rx ring.
595  */
596 int
597 t4_ring_intr_enable(mac_intr_handle_t intrh)
598 {
599 	struct sge_rxq *rxq = (struct sge_rxq *)intrh;
600 	struct adapter *sc = rxq->port->adapter;
601 	struct sge_iq *iq;
602 
603 	iq = &rxq->iq;
604 	RXQ_LOCK(rxq);
605 	iq->polling = 0;
606 	iq->state = IQS_IDLE;
607 	t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
608 		     V_SEINTARM(iq->intr_params) | V_INGRESSQID(iq->cntxt_id));
609 	RXQ_UNLOCK(rxq);
610 	return (0);
611 }
612 
613 /*
614  * Disable interrupt on the specificed rx ring.
615  */
616 int
617 t4_ring_intr_disable(mac_intr_handle_t intrh)
618 {
619 	struct sge_rxq *rxq = (struct sge_rxq *)intrh;
620 	struct sge_iq *iq;
621 
622 	/* Nothing to be done here wrt interrupt, as it
623 	 * will not fire, until we write back to
624 	 * A_SGE_PF_GTS.SEIntArm in t4_ring_intr_enable.
625 	 */
626 
627 	iq = &rxq->iq;
628 	RXQ_LOCK(rxq);
629 	iq->polling = 1;
630 	iq->state = IQS_BUSY;
631 	RXQ_UNLOCK(rxq);
632 	return (0);
633 }
634 
635 mblk_t *
636 t4_poll_ring(void *arg, int n_bytes)
637 {
638 	struct sge_rxq *rxq = (struct sge_rxq *)arg;
639 	mblk_t *mp = NULL;
640 
641 	ASSERT(n_bytes >= 0);
642 	if (n_bytes == 0)
643 		return (NULL);
644 
645 	RXQ_LOCK(rxq);
646 	mp = t4_ring_rx(rxq, n_bytes);
647 	RXQ_UNLOCK(rxq);
648 
649 	return (mp);
650 }
651 
652 /*
653  * Retrieve a value for one of the statistics for a particular rx ring
654  */
655 int
656 t4_rx_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
657 {
658 	struct sge_rxq *rxq = (struct sge_rxq *)rh;
659 
660 	switch (stat) {
661 	case MAC_STAT_RBYTES:
662 		*val = rxq->rxbytes;
663 		break;
664 
665 	case MAC_STAT_IPACKETS:
666 		*val = rxq->rxpkts;
667 		break;
668 
669 	default:
670 		*val = 0;
671 		return (ENOTSUP);
672 	}
673 
674 	return (0);
675 }
676 
677 /*
678  * Retrieve a value for one of the statistics for a particular tx ring
679  */
680 int
681 t4_tx_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
682 {
683 	struct sge_txq *txq = (struct sge_txq *)rh;
684 
685 	switch (stat) {
686 	case MAC_STAT_RBYTES:
687 		*val = txq->txbytes;
688 		break;
689 
690 	case MAC_STAT_IPACKETS:
691 		*val = txq->txpkts;
692 		break;
693 
694 	default:
695 		*val = 0;
696 		return (ENOTSUP);
697 	}
698 
699 	return (0);
700 }
701 
702 /*
703  * Callback funtion for MAC layer to register all rings
704  * for given ring_group, noted by group_index.
705  * Since we have only one group, ring index becomes
706  * absolute index.
707  */
708 void
709 t4_fill_ring(void *arg, mac_ring_type_t rtype, const int group_index,
710 	     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
711 {
712 	struct port_info *pi = arg;
713 	mac_intr_t *mintr;
714 
715 	switch (rtype) {
716 	case MAC_RING_TYPE_RX: {
717 		struct sge_rxq *rxq;
718 
719 		rxq = &pi->adapter->sge.rxq[pi->first_rxq + ring_index];
720 		rxq->ring_handle = rh;
721 
722 		infop->mri_driver = (mac_ring_driver_t)rxq;
723 		infop->mri_start = t4_ring_start;
724 		infop->mri_stop = NULL;
725 		infop->mri_poll = t4_poll_ring;
726 		infop->mri_stat = t4_rx_stat;
727 
728 		mintr = &infop->mri_intr;
729 		mintr->mi_handle = (mac_intr_handle_t)rxq;
730 		mintr->mi_enable = t4_ring_intr_enable;
731 		mintr->mi_disable = t4_ring_intr_disable;
732 
733 		break;
734 	}
735 	case MAC_RING_TYPE_TX: {
736 		struct sge_txq *txq = &pi->adapter->sge.txq[pi->first_txq + ring_index];
737 		txq->ring_handle = rh;
738 		infop->mri_driver = (mac_ring_driver_t)txq;
739 		infop->mri_start = NULL;
740 		infop->mri_stop = NULL;
741 		infop->mri_tx = t4_eth_tx;
742 		infop->mri_stat = t4_tx_stat;
743 		break;
744 	}
745 	default:
746 		ASSERT(0);
747 		break;
748 	}
749 }
750 
751 mblk_t *
752 t4_mc_tx(void *arg, mblk_t *m)
753 {
754 	struct port_info *pi = arg;
755 	struct adapter *sc = pi->adapter;
756 	struct sge_txq *txq = &sc->sge.txq[pi->first_txq];
757 
758 	return (t4_eth_tx(txq, m));
759 }
760 
761 static int
762 t4_mc_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
763 {
764 	struct port_info *pi = arg;
765 
766 	if (id != 0 || infop == NULL)
767 		return (EINVAL);
768 
769 	switch (pi->mod_type) {
770 	case FW_PORT_MOD_TYPE_NONE:
771 		mac_transceiver_info_set_present(infop, B_FALSE);
772 		break;
773 	case FW_PORT_MOD_TYPE_NOTSUPPORTED:
774 		mac_transceiver_info_set_present(infop, B_TRUE);
775 		mac_transceiver_info_set_usable(infop, B_FALSE);
776 		break;
777 	default:
778 		mac_transceiver_info_set_present(infop, B_TRUE);
779 		mac_transceiver_info_set_usable(infop, B_TRUE);
780 		break;
781 	}
782 
783 	return (0);
784 }
785 
786 static int
787 t4_mc_transceiver_read(void *arg, uint_t id, uint_t page, void *bp,
788     size_t nbytes, off_t offset, size_t *nread)
789 {
790 	struct port_info *pi = arg;
791 	struct adapter *sc = pi->adapter;
792 	int rc;
793 	size_t i, maxread;
794 	/* LINTED: E_FUNC_VAR_UNUSED */
795 	struct fw_ldst_cmd ldst __unused;
796 
797 	if (id != 0 || bp == NULL || nbytes == 0 || nread == NULL ||
798 	    (page != 0xa0 && page != 0xa2) || offset < 0)
799 		return (EINVAL);
800 
801 	if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256))
802 		return (EINVAL);
803 
804 	rc = begin_synchronized_op(pi, 0, 1);
805 	if (rc != 0)
806 		return (rc);
807 
808 	/*
809 	 * Firmware has a maximum size that we can read. Don't read more than it
810 	 * allows.
811 	 */
812 	maxread = sizeof (ldst.u.i2c.data);
813 	for (i = 0; i < nbytes; i += maxread) {
814 		size_t toread = MIN(maxread, nbytes - i);
815 		rc = -t4_i2c_rd(sc, sc->mbox, pi->port_id, page, offset, toread,
816 		    bp);
817 		if (rc != 0)
818 			break;
819 		offset += toread;
820 		bp = (void *)((uintptr_t)bp + toread);
821 	}
822 	end_synchronized_op(pi, 0);
823 	if (rc == 0)
824 		*nread = nbytes;
825 	return (rc);
826 }
827 
828 static int
829 t4_port_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
830 {
831 	struct port_info *pi = arg;
832 	struct adapter *sc = pi->adapter;
833 	int val, rc;
834 
835 	if (flags != 0)
836 		return (EINVAL);
837 
838 	switch (mode) {
839 	case MAC_LED_DEFAULT:
840 		val = 0;
841 		break;
842 	case MAC_LED_IDENT:
843 		val = 0xffff;
844 		break;
845 
846 	default:
847 		return (ENOTSUP);
848 	}
849 
850 	rc = begin_synchronized_op(pi, 1, 1);
851 	if (rc != 0)
852 		return (rc);
853 	rc = -t4_identify_port(sc, sc->mbox, pi->viid, val);
854 	end_synchronized_op(pi, 1);
855 
856 	return (rc);
857 }
858 
859 static boolean_t
860 t4_mc_getcapab(void *arg, mac_capab_t cap, void *data)
861 {
862 	struct port_info *pi = arg;
863 	boolean_t status = B_TRUE;
864 	mac_capab_transceiver_t *mct;
865 	mac_capab_led_t *mcl;
866 
867 	switch (cap) {
868 	case MAC_CAPAB_HCKSUM:
869 		if (pi->features & CXGBE_HW_CSUM) {
870 			uint32_t *d = data;
871 			*d = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM |
872 			    HCKSUM_INET_FULL_V6;
873 		} else
874 			status = B_FALSE;
875 		break;
876 
877 	case MAC_CAPAB_LSO:
878 		/* Enabling LSO requires Checksum offloading */
879 		if (pi->features & CXGBE_HW_LSO &&
880 		    pi->features & CXGBE_HW_CSUM) {
881 			mac_capab_lso_t *d = data;
882 
883 			d->lso_flags = LSO_TX_BASIC_TCP_IPV4 |
884 			    LSO_TX_BASIC_TCP_IPV6;
885 			d->lso_basic_tcp_ipv4.lso_max = 65535;
886 			d->lso_basic_tcp_ipv6.lso_max = 65535;
887 		} else
888 			status = B_FALSE;
889 		break;
890 
891 	case MAC_CAPAB_RINGS: {
892 		mac_capab_rings_t *cap_rings = data;
893 
894 		if (!pi->adapter->props.multi_rings) {
895 			status = B_FALSE;
896 			break;
897 		}
898 		switch (cap_rings->mr_type) {
899 		case MAC_RING_TYPE_RX:
900 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
901 			cap_rings->mr_rnum = pi->nrxq;
902 			cap_rings->mr_gnum = 1;
903 			cap_rings->mr_rget = t4_fill_ring;
904 			cap_rings->mr_gget = t4_fill_group;
905 			cap_rings->mr_gaddring = NULL;
906 			cap_rings->mr_gremring = NULL;
907 			break;
908 		case MAC_RING_TYPE_TX:
909 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
910 			cap_rings->mr_rnum = pi->ntxq;
911 			cap_rings->mr_gnum = 0;
912 			cap_rings->mr_rget = t4_fill_ring;
913 			cap_rings->mr_gget = NULL;
914 			break;
915 		}
916 		break;
917 	}
918 
919 	case MAC_CAPAB_TRANSCEIVER:
920 		mct = data;
921 
922 		mct->mct_flags = 0;
923 		mct->mct_ntransceivers = 1;
924 		mct->mct_info = t4_mc_transceiver_info;
925 		mct->mct_read = t4_mc_transceiver_read;
926 		break;
927 	case MAC_CAPAB_LED:
928 		mcl = data;
929 		mcl->mcl_flags = 0;
930 		mcl->mcl_modes = MAC_LED_DEFAULT | MAC_LED_IDENT;
931 		mcl->mcl_set = t4_port_led_set;
932 		break;
933 
934 	default:
935 		status = B_FALSE; /* cap not supported */
936 	}
937 
938 	return (status);
939 }
940 
941 static link_fec_t
942 fec_to_link_fec(cc_fec_t cc_fec)
943 {
944 	link_fec_t link_fec = 0;
945 
946 	if ((cc_fec & (FEC_RS | FEC_BASER_RS)) == (FEC_RS | FEC_BASER_RS))
947 		return (LINK_FEC_AUTO);
948 
949 	if ((cc_fec & FEC_NONE) != 0)
950 		link_fec |= LINK_FEC_NONE;
951 
952 	if ((cc_fec & FEC_AUTO) != 0)
953 		link_fec |= LINK_FEC_AUTO;
954 
955 	if ((cc_fec & FEC_RS) != 0)
956 		link_fec |= LINK_FEC_RS;
957 
958 	if ((cc_fec & FEC_BASER_RS) != 0)
959 		link_fec |= LINK_FEC_BASE_R;
960 
961 	return (link_fec);
962 }
963 
964 static int
965 link_fec_to_fec(int v)
966 {
967 	int fec = 0;
968 
969 	if ((v & LINK_FEC_AUTO) != 0) {
970 		fec = FEC_AUTO;
971 		v &= ~LINK_FEC_AUTO;
972 	} else {
973 		if ((v & LINK_FEC_NONE) != 0) {
974 			fec = FEC_NONE;
975 			v &= ~LINK_FEC_NONE;
976 		}
977 
978 		if ((v & LINK_FEC_RS) != 0) {
979 			fec |= FEC_RS;
980 			v &= ~LINK_FEC_RS;
981 		}
982 
983 		if ((v & LINK_FEC_BASE_R) != 0) {
984 			fec |= FEC_BASER_RS;
985 			v &= ~LINK_FEC_BASE_R;
986 		}
987 	}
988 
989 	if (v != 0)
990 		return (-1);
991 
992 	ASSERT3S(fec, !=, 0);
993 
994 	return (fec);
995 }
996 
997 /* ARGSUSED */
998 static int
999 t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id, uint_t size,
1000     const void *val)
1001 {
1002 	struct port_info *pi = arg;
1003 	struct adapter *sc = pi->adapter;
1004 	struct link_config lc_copy, *lc = &pi->link_cfg;
1005 	uint8_t v8 = *(uint8_t *)val;
1006 	uint32_t v32 = *(uint32_t *)val;
1007 	int old, new = 0, relink = 0, rx_mode = 0, rc = 0;
1008 	boolean_t down_link = B_TRUE;
1009 	link_flowctrl_t fc;
1010 	link_fec_t fec;
1011 
1012 	/*
1013 	 * Save a copy of link_config. This can be used to restore link_config
1014 	 * if t4_link_l1cfg() fails.
1015 	 */
1016 	bcopy(lc, &lc_copy, sizeof (struct link_config));
1017 
1018 	switch (id) {
1019 	case MAC_PROP_AUTONEG:
1020 		if (lc->pcaps & FW_PORT_CAP32_ANEG) {
1021 			old = lc->autoneg;
1022 			new = v8 ? AUTONEG_ENABLE : AUTONEG_DISABLE;
1023 			if (old != new) {
1024 				/* LINTED: E_CONSTANT_CONDITION */
1025 				lc->autoneg = new;
1026 				relink = 1;
1027 				if (new == AUTONEG_DISABLE) {
1028 					/* Only 100M is available */
1029 					lc->speed_caps =
1030 					    FW_PORT_CAP32_SPEED_100M;
1031 					lc->acaps =
1032 					    FW_PORT_CAP32_SPEED_100M;
1033 				} else {
1034 					/*
1035 					 * Advertise autonegotiation capability
1036 					 * along with supported speeds
1037 					 */
1038 					lc->acaps |= (FW_PORT_CAP32_ANEG |
1039 					    (lc->pcaps &
1040 					    (FW_PORT_CAP32_SPEED_100M |
1041 					    FW_PORT_CAP32_SPEED_1G)));
1042 					lc->speed_caps = 0;
1043 				}
1044 			}
1045 		} else
1046 			rc = ENOTSUP;
1047 		break;
1048 
1049 	case MAC_PROP_MTU:
1050 		if (v32 < 46 || v32 > MAX_MTU) {
1051 			rc = EINVAL;
1052 		} else if (v32 != pi->mtu) {
1053 			pi->mtu = v32;
1054 			(void) mac_maxsdu_update(pi->mh, v32);
1055 			rx_mode = 1;
1056 		}
1057 
1058 		break;
1059 
1060 	case MAC_PROP_FLOWCTRL:
1061 		fc = *(link_flowctrl_t *)val;
1062 		old = lc->requested_fc & (PAUSE_TX | PAUSE_RX);
1063 
1064 		if (fc == LINK_FLOWCTRL_BI)
1065 			new = (PAUSE_TX | PAUSE_RX);
1066 		else if (fc == LINK_FLOWCTRL_TX)
1067 			new = PAUSE_TX;
1068 		else if (fc == LINK_FLOWCTRL_RX)
1069 			new = PAUSE_RX;
1070 
1071 		if (new != old) {
1072 			lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
1073 			lc->requested_fc |= new;
1074 			relink = 1;
1075 		}
1076 		break;
1077 
1078 	case MAC_PROP_EN_FEC_CAP:
1079 		if (!fec_supported(lc->pcaps)) {
1080 			rc = ENOTSUP;
1081 			break;
1082 		}
1083 
1084 		fec = *(link_fec_t *)val;
1085 		new = link_fec_to_fec(fec);
1086 		if (new < 0) {
1087 			rc = EINVAL;
1088 		} else if (new != lc->requested_fec) {
1089 			lc->requested_fec = new;
1090 			relink = 1;
1091 			/*
1092 			 * For fec, do not preemptively force the link
1093 			 * down. If changing fec causes the link state
1094 			 * to transition, then appropriate asynchronous
1095 			 * events are generated which correctly reflect
1096 			 * the link state.
1097 			 */
1098 			down_link = B_FALSE;
1099 		}
1100 		break;
1101 
1102 	case MAC_PROP_EN_10GFDX_CAP:
1103 		if (lc->pcaps & FW_PORT_CAP32_ANEG && is_10G_port(pi)) {
1104 			old = lc->acaps & FW_PORT_CAP32_SPEED_10G;
1105 			new = v8 ? FW_PORT_CAP32_SPEED_10G : 0;
1106 			if (new != old) {
1107 				lc->acaps &= ~FW_PORT_CAP32_SPEED_10G;
1108 				lc->acaps |= new;
1109 				relink = 1;
1110 			}
1111 		} else
1112 			rc = ENOTSUP;
1113 
1114 		break;
1115 
1116 	case MAC_PROP_EN_1000FDX_CAP:
1117 		/* Forced 1G */
1118 		if (lc->autoneg == AUTONEG_ENABLE) {
1119 			old = lc->acaps & FW_PORT_CAP32_SPEED_1G;
1120 			new = v8 ? FW_PORT_CAP32_SPEED_1G : 0;
1121 
1122 			if (old != new) {
1123 				lc->acaps &= ~FW_PORT_CAP32_SPEED_1G;
1124 				lc->acaps |= new;
1125 				relink = 1;
1126 			}
1127 		} else
1128 			rc = ENOTSUP;
1129 		break;
1130 
1131 	case MAC_PROP_EN_100FDX_CAP:
1132 		/* Forced 100M */
1133 		if (lc->autoneg == AUTONEG_ENABLE) {
1134 			old = lc->acaps & FW_PORT_CAP32_SPEED_100M;
1135 			new = v8 ? FW_PORT_CAP32_SPEED_100M : 0;
1136 			if (old != new) {
1137 				lc->acaps &= ~FW_PORT_CAP32_SPEED_100M;
1138 				lc->acaps |= new;
1139 				relink = 1;
1140 			}
1141 		} else
1142 			rc = ENOTSUP;
1143 		break;
1144 
1145 	case MAC_PROP_PRIVATE:
1146 		rc = setprop(pi, name, val);
1147 		break;
1148 
1149 	default:
1150 		rc = ENOTSUP;
1151 	}
1152 
1153 	if (isset(&sc->open_device_map, pi->port_id) != 0) {
1154 		if (relink != 0) {
1155 			if (down_link)
1156 				t4_os_link_changed(pi->adapter, pi->port_id, 0);
1157 			rc = begin_synchronized_op(pi, 1, 1);
1158 			if (rc != 0)
1159 				return (rc);
1160 			rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan,
1161 			    &pi->link_cfg);
1162 			end_synchronized_op(pi, 1);
1163 			if (rc != 0) {
1164 				cxgb_printf(pi->dip, CE_WARN,
1165 				    "start_link failed:%d", rc);
1166 
1167 				/* Restore link_config */
1168 				bcopy(&lc_copy, lc,
1169 				    sizeof (struct link_config));
1170 			}
1171 		}
1172 
1173 		if (rx_mode != 0) {
1174 			rc = begin_synchronized_op(pi, 1, 1);
1175 			if (rc != 0)
1176 				return (rc);
1177 			rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v32, -1,
1178 			    -1, -1, -1, false);
1179 			end_synchronized_op(pi, 1);
1180 			if (rc != 0) {
1181 				cxgb_printf(pi->dip, CE_WARN,
1182 				    "set_rxmode failed: %d", rc);
1183 			}
1184 		}
1185 	}
1186 
1187 	return (rc);
1188 }
1189 
1190 static int
1191 t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t size,
1192     void *val)
1193 {
1194 	struct port_info *pi = arg;
1195 	struct link_config *lc = &pi->link_cfg;
1196 	uint8_t *u = val;
1197 
1198 	switch (id) {
1199 	case MAC_PROP_DUPLEX:
1200 		*(link_duplex_t *)val = lc->link_ok ? LINK_DUPLEX_FULL :
1201 		    LINK_DUPLEX_UNKNOWN;
1202 		break;
1203 
1204 	case MAC_PROP_SPEED:
1205 		if (lc->link_ok != 0) {
1206 			*(uint64_t *)val = lc->speed;
1207 			*(uint64_t *)val *= 1000000;
1208 		} else
1209 			*(uint64_t *)val = 0;
1210 		break;
1211 
1212 	case MAC_PROP_STATUS:
1213 		*(link_state_t *)val = lc->link_ok ? LINK_STATE_UP :
1214 		    LINK_STATE_DOWN;
1215 		break;
1216 
1217 	case MAC_PROP_AUTONEG:
1218 		*u = lc->autoneg == AUTONEG_ENABLE;
1219 		break;
1220 
1221 	case MAC_PROP_MTU:
1222 		*(uint32_t *)val = pi->mtu;
1223 		break;
1224 
1225 	case MAC_PROP_FLOWCTRL:
1226 		if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) ==
1227 		    (PAUSE_TX | PAUSE_RX))
1228 			*(link_flowctrl_t *)val = LINK_FLOWCTRL_BI;
1229 		else if (lc->requested_fc & PAUSE_TX)
1230 			*(link_flowctrl_t *)val = LINK_FLOWCTRL_TX;
1231 		else if (lc->requested_fc & PAUSE_RX)
1232 			*(link_flowctrl_t *)val = LINK_FLOWCTRL_RX;
1233 		else
1234 			*(link_flowctrl_t *)val = LINK_FLOWCTRL_NONE;
1235 		break;
1236 
1237 	case MAC_PROP_ADV_FEC_CAP:
1238 		if (!fec_supported(lc->pcaps))
1239 			return (ENOTSUP);
1240 
1241 		*(link_fec_t *)val = fec_to_link_fec(lc->fec);
1242 		break;
1243 
1244 	case MAC_PROP_EN_FEC_CAP:
1245 		if (!fec_supported(lc->pcaps))
1246 			return (ENOTSUP);
1247 
1248 		*(link_fec_t *)val = fec_to_link_fec(lc->requested_fec);
1249 		break;
1250 
1251 	case MAC_PROP_ADV_100GFDX_CAP:
1252 	case MAC_PROP_EN_100GFDX_CAP:
1253 		*u = !!(lc->acaps & FW_PORT_CAP32_SPEED_100G);
1254 		break;
1255 
1256 	case MAC_PROP_ADV_40GFDX_CAP:
1257 	case MAC_PROP_EN_40GFDX_CAP:
1258 		*u = !!(lc->acaps & FW_PORT_CAP32_SPEED_40G);
1259 		break;
1260 
1261 	case MAC_PROP_ADV_25GFDX_CAP:
1262 	case MAC_PROP_EN_25GFDX_CAP:
1263 		*u = !!(lc->acaps & FW_PORT_CAP32_SPEED_25G);
1264 		break;
1265 
1266 	case MAC_PROP_ADV_10GFDX_CAP:
1267 	case MAC_PROP_EN_10GFDX_CAP:
1268 		*u = !!(lc->acaps & FW_PORT_CAP32_SPEED_10G);
1269 		break;
1270 
1271 	case MAC_PROP_ADV_1000FDX_CAP:
1272 	case MAC_PROP_EN_1000FDX_CAP:
1273 		*u = !!(lc->acaps & FW_PORT_CAP32_SPEED_1G);
1274 		break;
1275 
1276 	case MAC_PROP_ADV_100FDX_CAP:
1277 	case MAC_PROP_EN_100FDX_CAP:
1278 		*u = !!(lc->acaps & FW_PORT_CAP32_SPEED_100M);
1279 		break;
1280 
1281 	case MAC_PROP_PRIVATE:
1282 		return (getprop(pi, name, size, val));
1283 
1284 	default:
1285 		return (ENOTSUP);
1286 	}
1287 
1288 	return (0);
1289 }
1290 
1291 static void
1292 t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id,
1293     mac_prop_info_handle_t ph)
1294 {
1295 	struct port_info *pi = arg;
1296 	struct link_config *lc = &pi->link_cfg;
1297 
1298 	switch (id) {
1299 	case MAC_PROP_DUPLEX:
1300 	case MAC_PROP_SPEED:
1301 	case MAC_PROP_STATUS:
1302 		mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1303 		break;
1304 
1305 	case MAC_PROP_AUTONEG:
1306 		if (lc->pcaps & FW_PORT_CAP32_ANEG)
1307 			mac_prop_info_set_default_uint8(ph, 1);
1308 		else
1309 			mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1310 		break;
1311 
1312 	case MAC_PROP_MTU:
1313 		mac_prop_info_set_range_uint32(ph, 46, MAX_MTU);
1314 		break;
1315 
1316 	case MAC_PROP_FLOWCTRL:
1317 		mac_prop_info_set_default_link_flowctrl(ph, LINK_FLOWCTRL_BI);
1318 		break;
1319 
1320 	case MAC_PROP_EN_FEC_CAP:
1321 		mac_prop_info_set_default_fec(ph, LINK_FEC_AUTO);
1322 		break;
1323 
1324 	case MAC_PROP_ADV_FEC_CAP:
1325 		mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1326 		mac_prop_info_set_default_fec(ph, LINK_FEC_AUTO);
1327 		break;
1328 
1329 	case MAC_PROP_EN_10GFDX_CAP:
1330 		if (lc->pcaps & FW_PORT_CAP32_ANEG &&
1331 		    lc->pcaps & FW_PORT_CAP32_SPEED_10G)
1332 			mac_prop_info_set_default_uint8(ph, 1);
1333 		else
1334 			mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1335 		break;
1336 
1337 	case MAC_PROP_EN_1000FDX_CAP:
1338 		if (lc->pcaps & FW_PORT_CAP32_ANEG &&
1339 		    lc->pcaps & FW_PORT_CAP32_SPEED_1G)
1340 			mac_prop_info_set_default_uint8(ph, 1);
1341 		else
1342 			mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1343 		break;
1344 
1345 	case MAC_PROP_EN_100FDX_CAP:
1346 		if (lc->pcaps & FW_PORT_CAP32_ANEG &&
1347 		    lc->pcaps & FW_PORT_CAP32_SPEED_100M)
1348 			mac_prop_info_set_default_uint8(ph, 1);
1349 		else
1350 			mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1351 		break;
1352 
1353 	case MAC_PROP_ADV_10GFDX_CAP:
1354 	case MAC_PROP_ADV_1000FDX_CAP:
1355 	case MAC_PROP_ADV_100FDX_CAP:
1356 		mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1357 		break;
1358 
1359 	case MAC_PROP_PRIVATE:
1360 		propinfo(pi, name, ph);
1361 		break;
1362 
1363 	default:
1364 		break;
1365 	}
1366 }
1367 
1368 int
1369 begin_synchronized_op(struct port_info *pi, int hold, int waitok)
1370 {
1371 	struct adapter *sc = pi->adapter;
1372 	int rc = 0;
1373 
1374 	ADAPTER_LOCK(sc);
1375 	while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
1376 		if (!waitok) {
1377 			rc = EBUSY;
1378 			goto failed;
1379 		} else if (cv_wait_sig(&sc->cv, &sc->lock) == 0) {
1380 			rc = EINTR;
1381 			goto failed;
1382 		}
1383 	}
1384 	if (IS_DOOMED(pi) != 0) {	/* shouldn't happen on Solaris */
1385 		rc = ENXIO;
1386 		goto failed;
1387 	}
1388 	ASSERT(!IS_BUSY(sc));
1389 	/* LINTED: E_CONSTANT_CONDITION */
1390 	SET_BUSY(sc);
1391 
1392 	if (!hold)
1393 		ADAPTER_UNLOCK(sc);
1394 
1395 	return (0);
1396 failed:
1397 	ADAPTER_UNLOCK(sc);
1398 	return (rc);
1399 }
1400 
1401 void
1402 end_synchronized_op(struct port_info *pi, int held)
1403 {
1404 	struct adapter *sc = pi->adapter;
1405 
1406 	if (!held)
1407 		ADAPTER_LOCK(sc);
1408 
1409 	ADAPTER_LOCK_ASSERT_OWNED(sc);
1410 	ASSERT(IS_BUSY(sc));
1411 	/* LINTED: E_CONSTANT_CONDITION */
1412 	CLR_BUSY(sc);
1413 	cv_signal(&sc->cv);
1414 	ADAPTER_UNLOCK(sc);
1415 }
1416 
1417 static int
1418 t4_init_synchronized(struct port_info *pi)
1419 {
1420 	struct adapter *sc = pi->adapter;
1421 	int rc = 0;
1422 
1423 	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1424 
1425 	if (isset(&sc->open_device_map, pi->port_id) != 0)
1426 		return (0);	/* already running */
1427 
1428 	if (!(sc->flags & FULL_INIT_DONE) &&
1429 	    ((rc = adapter_full_init(sc)) != 0))
1430 		return (rc);	/* error message displayed already */
1431 
1432 	if (!(pi->flags & PORT_INIT_DONE)) {
1433 		rc = port_full_init(pi);
1434 		if (rc != 0)
1435 			return (rc); /* error message displayed already */
1436 	} else
1437 		enable_port_queues(pi);
1438 
1439 	rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, pi->mtu, 0, 0, 1, 0, false);
1440 	if (rc != 0) {
1441 		cxgb_printf(pi->dip, CE_WARN, "set_rxmode failed: %d", rc);
1442 		goto done;
1443 	}
1444 	rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt,
1445 	    pi->hw_addr, true, &pi->smt_idx);
1446 	if (rc < 0) {
1447 		cxgb_printf(pi->dip, CE_WARN, "change_mac failed: %d", rc);
1448 		rc = -rc;
1449 		goto done;
1450 	} else
1451 		/* LINTED: E_ASSIGN_NARROW_CONV */
1452 		pi->xact_addr_filt = rc;
1453 
1454 	rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
1455 	if (rc != 0) {
1456 		cxgb_printf(pi->dip, CE_WARN, "start_link failed: %d", rc);
1457 		goto done;
1458 	}
1459 
1460 	rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true);
1461 	if (rc != 0) {
1462 		cxgb_printf(pi->dip, CE_WARN, "enable_vi failed: %d", rc);
1463 		goto done;
1464 	}
1465 
1466 	/* all ok */
1467 	setbit(&sc->open_device_map, pi->port_id);
1468 done:
1469 	if (rc != 0)
1470 		(void) t4_uninit_synchronized(pi);
1471 
1472 	return (rc);
1473 }
1474 
1475 /*
1476  * Idempotent.
1477  */
1478 static int
1479 t4_uninit_synchronized(struct port_info *pi)
1480 {
1481 	struct adapter *sc = pi->adapter;
1482 	int rc;
1483 
1484 	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1485 
1486 	/*
1487 	 * Disable the VI so that all its data in either direction is discarded
1488 	 * by the MPS.  Leave everything else (the queues, interrupts, and 1Hz
1489 	 * tick) intact as the TP can deliver negative advice or data that it's
1490 	 * holding in its RAM (for an offloaded connection) even after the VI is
1491 	 * disabled.
1492 	 */
1493 	rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false);
1494 	if (rc != 0) {
1495 		cxgb_printf(pi->dip, CE_WARN, "disable_vi failed: %d", rc);
1496 		return (rc);
1497 	}
1498 
1499 	disable_port_queues(pi);
1500 
1501 	clrbit(&sc->open_device_map, pi->port_id);
1502 
1503 	pi->link_cfg.link_ok = 0;
1504 	pi->link_cfg.speed = 0;
1505 	mac_link_update(pi->mh, LINK_STATE_UNKNOWN);
1506 
1507 	return (0);
1508 }
1509 
1510 static void
1511 propinfo(struct port_info *pi, const char *name, mac_prop_info_handle_t ph)
1512 {
1513 	struct adapter *sc = pi->adapter;
1514 	struct driver_properties *p = &sc->props;
1515 	struct link_config *lc = &pi->link_cfg;
1516 	int v;
1517 	char str[16];
1518 
1519 	if (strcmp(name, T4PROP_TMR_IDX) == 0)
1520 		v = is_10G_port(pi) ? p->tmr_idx_10g : p->tmr_idx_1g;
1521 	else if (strcmp(name, T4PROP_PKTC_IDX) == 0)
1522 		v = is_10G_port(pi) ? p->pktc_idx_10g : p->pktc_idx_1g;
1523 	else if (strcmp(name, T4PROP_HW_CSUM) == 0)
1524 		v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0;
1525 	else if (strcmp(name, T4PROP_HW_LSO) == 0)
1526 		v = (pi->features & CXGBE_HW_LSO) ? 1 : 0;
1527 	else if (strcmp(name, T4PROP_TX_PAUSE) == 0)
1528 		v = (lc->fc & PAUSE_TX) ? 1 : 0;
1529 	else if (strcmp(name, T4PROP_RX_PAUSE) == 0)
1530 		v = (lc->fc & PAUSE_RX) ? 1 : 0;
1531 #if MAC_VERSION == 1
1532 	else if (strcmp(name, T4PROP_MTU) == 0)
1533 		v = ETHERMTU;
1534 #endif
1535 	else
1536 		return;
1537 
1538 	(void) snprintf(str, sizeof (str), "%d", v);
1539 	mac_prop_info_set_default_str(ph, str);
1540 }
1541 
1542 static int
1543 getprop(struct port_info *pi, const char *name, uint_t size, void *val)
1544 {
1545 	struct link_config *lc = &pi->link_cfg;
1546 	int v;
1547 
1548 	if (strcmp(name, T4PROP_TMR_IDX) == 0)
1549 		v = pi->tmr_idx;
1550 	else if (strcmp(name, T4PROP_PKTC_IDX) == 0)
1551 		v = pi->pktc_idx;
1552 	else if (strcmp(name, T4PROP_HW_CSUM) == 0)
1553 		v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0;
1554 	else if (strcmp(name, T4PROP_HW_LSO) == 0)
1555 		v = (pi->features & CXGBE_HW_LSO) ? 1 : 0;
1556 	else if (strcmp(name, T4PROP_TX_PAUSE) == 0)
1557 		v = (lc->fc & PAUSE_TX) ? 1 : 0;
1558 	else if (strcmp(name, T4PROP_RX_PAUSE) == 0)
1559 		v = (lc->fc & PAUSE_RX) ? 1 : 0;
1560 #if MAC_VERSION == 1
1561 	else if (strcmp(name, T4PROP_MTU) == 0)
1562 		v = pi->mtu;
1563 #endif
1564 	else
1565 		return (ENOTSUP);
1566 
1567 	(void) snprintf(val, size, "%d", v);
1568 	return (0);
1569 }
1570 
1571 static int
1572 setprop(struct port_info *pi, const char *name, const void *val)
1573 {
1574 	struct adapter *sc = pi->adapter;
1575 	long v;
1576 	int i, rc = 0, relink = 0, rx_mode = 0;
1577 	struct sge_rxq *rxq;
1578 	struct link_config lc_old, *lc = &pi->link_cfg;
1579 
1580 	/*
1581 	 * Save a copy of link_config. This can be used to restore link_config
1582 	 * if t4_link_l1cfg() fails.
1583 	 */
1584 	bcopy(lc, &lc_old, sizeof (struct link_config));
1585 
1586 	(void) ddi_strtol(val, NULL, 0, &v);
1587 
1588 	if (strcmp(name, T4PROP_TMR_IDX) == 0) {
1589 		if (v < 0 || v >= SGE_NTIMERS)
1590 			return (EINVAL);
1591 		if (v == pi->tmr_idx)
1592 			return (0);
1593 
1594 		/* LINTED: E_ASSIGN_NARROW_CONV */
1595 		pi->tmr_idx = v;
1596 		for_each_rxq(pi, i, rxq) {
1597 			rxq->iq.intr_params = V_QINTR_TIMER_IDX(v) |
1598 			    V_QINTR_CNT_EN(pi->pktc_idx >= 0);
1599 		}
1600 
1601 	} else if (strcmp(name, T4PROP_PKTC_IDX) == 0) {
1602 		if (v >= SGE_NCOUNTERS)
1603 			return (EINVAL);
1604 		if (v == pi->pktc_idx || (v < 0 && pi->pktc_idx == -1))
1605 			return (0);
1606 
1607 		/* LINTED: E_ASSIGN_NARROW_CONV */
1608 		pi->pktc_idx = v < 0 ? -1 : v;
1609 		for_each_rxq(pi, i, rxq) {
1610 			rxq->iq.intr_params = V_QINTR_TIMER_IDX(pi->tmr_idx) |
1611 			    /* takes effect right away */
1612 			    V_QINTR_CNT_EN(v >= 0);
1613 			/* LINTED: E_ASSIGN_NARROW_CONV */
1614 			rxq->iq.intr_pktc_idx = v; /* this needs fresh plumb */
1615 		}
1616 	} else if (strcmp(name, T4PROP_HW_CSUM) == 0) {
1617 		if (v != 0 && v != 1)
1618 			return (EINVAL);
1619 		if (v == 1)
1620 			pi->features |= CXGBE_HW_CSUM;
1621 		else
1622 			pi->features &= ~CXGBE_HW_CSUM;
1623 	} else if (strcmp(name, T4PROP_HW_LSO) == 0) {
1624 		if (v != 0 && v != 1)
1625 			return (EINVAL);
1626 		if (v == 1)
1627 			pi->features |= CXGBE_HW_LSO;
1628 		else
1629 			pi->features &= ~CXGBE_HW_LSO;
1630 	} else if (strcmp(name, T4PROP_TX_PAUSE) == 0) {
1631 		if (v != 0 && v != 1)
1632 			return (EINVAL);
1633 
1634 		if (v != 0)
1635 			lc->requested_fc |= PAUSE_TX;
1636 		else
1637 			lc->requested_fc &= ~PAUSE_TX;
1638 
1639 		relink = 1;
1640 
1641 	} else if (strcmp(name, T4PROP_RX_PAUSE) == 0) {
1642 		if (v != 0 && v != 1)
1643 			return (EINVAL);
1644 
1645 		if (v != 0)
1646 			lc->requested_fc |= PAUSE_RX;
1647 		else
1648 			lc->requested_fc &= ~PAUSE_RX;
1649 
1650 		relink = 1;
1651 	}
1652 #if MAC_VERSION == 1
1653 	else if (strcmp(name, T4PROP_MTU) == 0) {
1654 		if (v < 46 || v > MAX_MTU)
1655 			return (EINVAL);
1656 		if (v == pi->mtu)
1657 			return (0);
1658 
1659 		pi->mtu = (int)v;
1660 		(void) mac_maxsdu_update(pi->mh, v);
1661 		rx_mode = 1;
1662 	}
1663 #endif
1664 	else
1665 		return (ENOTSUP);
1666 
1667 	if (!(relink || rx_mode))
1668 		return (0);
1669 
1670 	/* If we are here, either relink or rx_mode is 1 */
1671 	if (isset(&sc->open_device_map, pi->port_id) != 0) {
1672 		if (relink != 0) {
1673 			rc = begin_synchronized_op(pi, 1, 1);
1674 			if (rc != 0)
1675 				return (rc);
1676 			rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
1677 			end_synchronized_op(pi, 1);
1678 			if (rc != 0) {
1679 				cxgb_printf(pi->dip, CE_WARN,
1680 				    "start_link failed:%d", rc);
1681 				/* Restore link_config */
1682 				bcopy(&lc_old, lc, sizeof (struct link_config));
1683 			}
1684 		} else if (rx_mode != 0) {
1685 			rc = begin_synchronized_op(pi, 1, 1);
1686 			if (rc != 0)
1687 				return (rc);
1688 			rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v, -1, -1,
1689 			    -1, -1, false);
1690 			end_synchronized_op(pi, 1);
1691 			if (rc != 0)  {
1692 				cxgb_printf(pi->dip, CE_WARN,
1693 				    "set_rxmode failed: %d", rc);
1694 			}
1695 		}
1696 		return (rc);
1697 	}
1698 
1699 	return (0);
1700 }
1701 
1702 void
1703 t4_mc_init(struct port_info *pi)
1704 {
1705 	pi->props = t4_priv_props;
1706 }
1707 
1708 void
1709 t4_mc_cb_init(struct port_info *pi)
1710 {
1711 	if (pi->adapter->props.multi_rings)
1712 		pi->mc = &t4_m_ring_callbacks;
1713 	else
1714 		pi->mc = &t4_m_callbacks;
1715 }
1716 
1717 void
1718 t4_os_link_changed(struct adapter *sc, int idx, int link_stat)
1719 {
1720 	struct port_info *pi = sc->port[idx];
1721 
1722 	mac_link_update(pi->mh, link_stat ? LINK_STATE_UP : LINK_STATE_DOWN);
1723 }
1724 
1725 /* ARGSUSED */
1726 void
1727 t4_mac_rx(struct port_info *pi, struct sge_rxq *rxq, mblk_t *m)
1728 {
1729 	mac_rx(pi->mh, NULL, m);
1730 }
1731 
1732 void
1733 t4_mac_tx_update(struct port_info *pi, struct sge_txq *txq)
1734 {
1735 	if (pi->adapter->props.multi_rings)
1736 		mac_tx_ring_update(pi->mh, txq->ring_handle);
1737 	else
1738 		mac_tx_update(pi->mh);
1739 }
1740