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