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