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