8867 add MAC_CAPAB_TRANSCEIVER support for cxgbe
[unleashed.git] / usr / src / uts / common / io / cxgbe / t4nex / t4_mac.c
blob0ec67c8d19b11a385f84fd41d7a99023204baf84
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.
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.
13 * This file is part of the Chelsio T4 support code.
15 * Copyright (C) 2010-2013 Chelsio Communications. All rights reserved.
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.
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>
31 #include "common/common.h"
32 #include "common/t4_regs.h"
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);
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);
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,
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.
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,
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"
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
114 static int
115 t4_mc_getstat(void *arg, uint_t stat, uint64_t *val)
117 struct port_info *pi = arg;
118 struct adapter *sc = pi->adapter;
119 struct link_config *lc = &pi->link_cfg;
121 #define GET_STAT(name) \
122 t4_read_reg64(sc, PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_##name##_L))
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;
133 case MAC_STAT_MULTIRCV:
134 *val = GET_STAT(RX_PORT_MCAST);
135 break;
137 case MAC_STAT_BRDCSTRCV:
138 *val = GET_STAT(RX_PORT_BCAST);
139 break;
141 case MAC_STAT_MULTIXMT:
142 *val = GET_STAT(TX_PORT_MCAST);
143 break;
145 case MAC_STAT_BRDCSTXMT:
146 *val = GET_STAT(TX_PORT_BCAST);
147 break;
149 case MAC_STAT_NORCVBUF:
150 *val = 0; /* TODO should come from rxq->nomem */
151 break;
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;
162 case MAC_STAT_UNKNOWNS:
163 return (ENOTSUP);
165 case MAC_STAT_NOXMTBUF:
166 *val = GET_STAT(TX_PORT_DROP);
167 break;
169 case MAC_STAT_OERRORS:
170 *val = GET_STAT(TX_PORT_ERROR);
171 break;
173 case MAC_STAT_COLLISIONS:
174 return (ENOTSUP);
176 case MAC_STAT_RBYTES:
177 *val = GET_STAT(RX_PORT_BYTES);
178 break;
180 case MAC_STAT_IPACKETS:
181 *val = GET_STAT(RX_PORT_FRAMES);
182 break;
184 case MAC_STAT_OBYTES:
185 *val = GET_STAT(TX_PORT_BYTES);
186 break;
188 case MAC_STAT_OPACKETS:
189 *val = GET_STAT(TX_PORT_FRAMES);
190 break;
192 case ETHER_STAT_ALIGN_ERRORS:
193 return (ENOTSUP);
195 case ETHER_STAT_FCS_ERRORS:
196 *val = GET_STAT(RX_PORT_CRC_ERROR);
197 break;
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);
207 case ETHER_STAT_MACXMT_ERRORS:
208 *val = GET_STAT(TX_PORT_ERROR);
209 break;
211 case ETHER_STAT_CARRIER_ERRORS:
212 return (ENOTSUP);
214 case ETHER_STAT_TOOLONG_ERRORS:
215 *val = GET_STAT(RX_PORT_MTU_ERROR);
216 break;
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;
227 case ETHER_STAT_XCVR_ADDR:
228 case ETHER_STAT_XCVR_ID:
229 case ETHER_STAT_XCVR_INUSE:
230 return (ENOTSUP);
232 case ETHER_STAT_CAP_100GFDX:
233 *val = !!(lc->supported & FW_PORT_CAP_SPEED_100G);
234 break;
236 case ETHER_STAT_CAP_40GFDX:
237 *val = !!(lc->supported & FW_PORT_CAP_SPEED_40G);
238 break;
240 case ETHER_STAT_CAP_25GFDX:
241 *val = !!(lc->supported & FW_PORT_CAP_SPEED_25G);
242 break;
244 case ETHER_STAT_CAP_10GFDX:
245 *val = !!(lc->supported & FW_PORT_CAP_SPEED_10G);
246 break;
248 case ETHER_STAT_CAP_1000FDX:
249 *val = !!(lc->supported & FW_PORT_CAP_SPEED_1G);
250 break;
252 case ETHER_STAT_CAP_1000HDX:
253 return (ENOTSUP);
255 case ETHER_STAT_CAP_100FDX:
256 *val = !!(lc->supported & FW_PORT_CAP_SPEED_100M);
257 break;
259 case ETHER_STAT_CAP_100HDX:
260 return (ENOTSUP);
262 case ETHER_STAT_CAP_10FDX:
263 case ETHER_STAT_CAP_10HDX:
264 return (ENOTSUP);
266 case ETHER_STAT_CAP_ASMPAUSE:
267 *val = 0;
268 break;
270 case ETHER_STAT_CAP_PAUSE:
271 *val = 1;
272 break;
274 case ETHER_STAT_CAP_AUTONEG:
275 *val = !!(lc->supported & FW_PORT_CAP_ANEG);
276 break;
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.
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
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 * +----------------------------+----------------------------------+
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;
306 /* Advertised pause capability */
307 case ETHER_STAT_ADV_CAP_PAUSE:
308 *val = (lc->requested_fc & PAUSE_TX) ? 1 : 0;
309 break;
311 case ETHER_STAT_ADV_CAP_100GFDX:
312 *val = !!(lc->advertising & FW_PORT_CAP_SPEED_100G);
313 break;
315 case ETHER_STAT_ADV_CAP_40GFDX:
316 *val = !!(lc->advertising & FW_PORT_CAP_SPEED_40G);
317 break;
319 case ETHER_STAT_ADV_CAP_25GFDX:
320 *val = !!(lc->advertising & FW_PORT_CAP_SPEED_25G);
321 break;
323 case ETHER_STAT_ADV_CAP_10GFDX:
324 *val = !!(lc->advertising & FW_PORT_CAP_SPEED_10G);
325 break;
327 case ETHER_STAT_ADV_CAP_1000FDX:
328 *val = !!(lc->advertising & FW_PORT_CAP_SPEED_1G);
329 break;
331 case ETHER_STAT_ADV_CAP_AUTONEG:
332 *val = !!(lc->advertising & FW_PORT_CAP_ANEG);
333 break;
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 */
343 case ETHER_STAT_LP_CAP_100GFDX:
344 *val = !!(lc->lp_advertising & FW_PORT_CAP_SPEED_100G);
345 break;
347 case ETHER_STAT_LP_CAP_40GFDX:
348 *val = !!(lc->lp_advertising & FW_PORT_CAP_SPEED_40G);
349 break;
351 case ETHER_STAT_LP_CAP_25GFDX:
352 *val = !!(lc->lp_advertising & FW_PORT_CAP_SPEED_25G);
353 break;
355 case ETHER_STAT_LP_CAP_10GFDX:
356 *val = !!(lc->lp_advertising & FW_PORT_CAP_SPEED_10G);
357 break;
359 case ETHER_STAT_LP_CAP_1000FDX:
360 *val = !!(lc->lp_advertising & FW_PORT_CAP_SPEED_1G);
361 break;
363 case ETHER_STAT_LP_CAP_AUTONEG:
364 *val = !!(lc->lp_advertising & FW_PORT_CAP_ANEG);
365 break;
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);
376 case ETHER_STAT_LINK_ASMPAUSE:
377 *val = 0;
378 break;
380 case ETHER_STAT_LINK_PAUSE:
381 *val = 1;
382 break;
384 case ETHER_STAT_LINK_AUTONEG:
385 *val = lc->autoneg == AUTONEG_ENABLE;
386 break;
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;
395 default:
396 #ifdef DEBUG
397 cxgb_printf(pi->dip, CE_NOTE, "stat %d not implemented.", stat);
398 #endif
399 return (ENOTSUP);
401 #undef GET_STAT
403 return (0);
406 static int
407 t4_mc_start(void *arg)
409 struct port_info *pi = arg;
410 int rc;
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);
418 return (rc);
421 static void
422 t4_mc_stop(void *arg)
424 struct port_info *pi = arg;
426 while (begin_synchronized_op(pi, 0, 1) != 0)
427 continue;
428 (void) t4_uninit_synchronized(pi);
429 end_synchronized_op(pi, 0);
432 static int
433 t4_mc_setpromisc(void *arg, boolean_t on)
435 struct port_info *pi = arg;
436 struct adapter *sc = pi->adapter;
437 int rc;
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);
446 return (rc);
450 * TODO: Starts failing as soon as the 336 entry table fills up. Need to use
451 * hash in that case.
453 static int
454 t4_mc_multicst(void *arg, boolean_t add, const uint8_t *mcaddr)
456 struct port_info *pi = arg;
457 struct adapter *sc = pi->adapter;
458 struct fw_vi_mac_cmd c;
459 int len16, rc;
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);
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
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.
484 else {
485 uint16_t idx;
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);
493 #endif
495 return (0);
499 t4_mc_unicst(void *arg, const uint8_t *ucaddr)
501 struct port_info *pi = arg;
502 struct adapter *sc = pi->adapter;
503 int rc;
505 if (ucaddr == NULL)
506 return (EINVAL);
508 rc = begin_synchronized_op(pi, 1, 1);
509 if (rc != 0)
510 return (rc);
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);
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;
526 end_synchronized_op(pi, 1);
528 return (rc);
532 t4_addmac(void *arg, const uint8_t *ucaddr)
534 return (t4_mc_unicst(arg, ucaddr));
537 static int
538 t4_remmac(void *arg, const uint8_t *mac_addr)
540 struct port_info *pi = arg;
541 int rc;
543 rc = begin_synchronized_op(pi, 1, 1);
544 if (rc != 0)
545 return (rc);
547 pi->macaddr_cnt--;
548 end_synchronized_op(pi, 1);
550 return (0);
554 * Callback funtion for MAC layer to register all groups.
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)
560 struct port_info *pi = arg;
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;
572 case MAC_RING_TYPE_TX:
573 default:
574 ASSERT(0);
575 break;
579 static int
580 t4_ring_start(mac_ring_driver_t rh, uint64_t mr_gen_num)
582 struct sge_rxq *rxq = (struct sge_rxq *)rh;
584 RXQ_LOCK(rxq);
585 rxq->ring_gen_num = mr_gen_num;
586 RXQ_UNLOCK(rxq);
587 return (0);
591 * Enable interrupt on the specificed rx ring.
594 t4_ring_intr_enable(mac_intr_handle_t intrh)
596 struct sge_rxq *rxq = (struct sge_rxq *)intrh;
597 struct adapter *sc = rxq->port->adapter;
598 struct sge_iq *iq;
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);
611 * Disable interrupt on the specificed rx ring.
614 t4_ring_intr_disable(mac_intr_handle_t intrh)
616 struct sge_rxq *rxq = (struct sge_rxq *)intrh;
617 struct sge_iq *iq;
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.
624 iq = &rxq->iq;
625 RXQ_LOCK(rxq);
626 iq->polling = 1;
627 iq->state = IQS_BUSY;
628 RXQ_UNLOCK(rxq);
629 return (0);
632 mblk_t *
633 t4_poll_ring(void *arg, int n_bytes)
635 struct sge_rxq *rxq = (struct sge_rxq *)arg;
636 mblk_t *mp = NULL;
638 ASSERT(n_bytes >= 0);
639 if (n_bytes == 0)
640 return (NULL);
642 RXQ_LOCK(rxq);
643 mp = t4_ring_rx(rxq, n_bytes);
644 RXQ_UNLOCK(rxq);
646 return (mp);
650 * Retrieve a value for one of the statistics for a particular rx ring
653 t4_rx_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
655 struct sge_rxq *rxq = (struct sge_rxq *)rh;
657 switch (stat) {
658 case MAC_STAT_RBYTES:
659 *val = rxq->rxbytes;
660 break;
662 case MAC_STAT_IPACKETS:
663 *val = rxq->rxpkts;
664 break;
666 default:
667 *val = 0;
668 return (ENOTSUP);
671 return (0);
675 * Retrieve a value for one of the statistics for a particular tx ring
678 t4_tx_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
680 struct sge_txq *txq = (struct sge_txq *)rh;
682 switch (stat) {
683 case MAC_STAT_RBYTES:
684 *val = txq->txbytes;
685 break;
687 case MAC_STAT_IPACKETS:
688 *val = txq->txpkts;
689 break;
691 default:
692 *val = 0;
693 return (ENOTSUP);
696 return (0);
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.
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)
709 struct port_info *pi = arg;
710 mac_intr_t *mintr;
712 switch (rtype) {
713 case MAC_RING_TYPE_RX: {
714 struct sge_rxq *rxq;
716 rxq = &pi->adapter->sge.rxq[pi->first_rxq + ring_index];
717 rxq->ring_handle = rh;
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;
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;
730 break;
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;
742 default:
743 ASSERT(0);
744 break;
748 mblk_t *
749 t4_mc_tx(void *arg, mblk_t *m)
751 struct port_info *pi = arg;
752 struct adapter *sc = pi->adapter;
753 struct sge_txq *txq = &sc->sge.txq[pi->first_txq];
755 return (t4_eth_tx(txq, m));
758 static int
759 t4_mc_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
761 struct port_info *pi = arg;
763 if (id != 0 || infop == NULL)
764 return (EINVAL);
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;
780 return (0);
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)
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;
794 if (id != 0 || bp == NULL || nbytes == 0 || nread == NULL ||
795 (page != 0xa0 && page != 0xa2) || offset < 0)
796 return (EINVAL);
798 if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256))
799 return (EINVAL);
801 rc = begin_synchronized_op(pi, 0, 1);
802 if (rc != 0)
803 return (rc);
806 * Firmware has a maximum size that we can read. Don't read more than it
807 * allows.
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);
819 end_synchronized_op(pi, 0);
820 if (rc == 0)
821 *nread = nbytes;
822 return (rc);
825 static boolean_t
826 t4_mc_getcapab(void *arg, mac_capab_t cap, void *data)
828 struct port_info *pi = arg;
829 boolean_t status = B_TRUE;
830 mac_capab_transceiver_t *mct;
832 switch (cap) {
833 case MAC_CAPAB_HCKSUM:
834 if (pi->features & CXGBE_HW_CSUM) {
835 uint32_t *d = data;
836 *d = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM;
837 } else
838 status = B_FALSE;
839 break;
841 case MAC_CAPAB_LSO:
842 /* Enabling LSO requires Checksum offloading */
843 if (pi->features & CXGBE_HW_LSO &&
844 pi->features & CXGBE_HW_CSUM) {
845 mac_capab_lso_t *d = data;
847 d->lso_flags = LSO_TX_BASIC_TCP_IPV4;
848 d->lso_basic_tcp_ipv4.lso_max = 65535;
849 } else
850 status = B_FALSE;
851 break;
853 case MAC_CAPAB_RINGS: {
854 mac_capab_rings_t *cap_rings = data;
856 if (!pi->adapter->props.multi_rings) {
857 status = B_FALSE;
858 break;
860 switch (cap_rings->mr_type) {
861 case MAC_RING_TYPE_RX:
862 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
863 cap_rings->mr_rnum = pi->nrxq;
864 cap_rings->mr_gnum = 1;
865 cap_rings->mr_rget = t4_fill_ring;
866 cap_rings->mr_gget = t4_fill_group;
867 cap_rings->mr_gaddring = NULL;
868 cap_rings->mr_gremring = NULL;
869 break;
870 case MAC_RING_TYPE_TX:
871 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
872 cap_rings->mr_rnum = pi->ntxq;
873 cap_rings->mr_gnum = 0;
874 cap_rings->mr_rget = t4_fill_ring;
875 cap_rings->mr_gget = NULL;
876 break;
878 break;
881 case MAC_CAPAB_TRANSCEIVER:
882 mct = data;
884 mct->mct_flags = 0;
885 mct->mct_ntransceivers = 1;
886 mct->mct_info = t4_mc_transceiver_info;
887 mct->mct_read = t4_mc_transceiver_read;
888 break;
890 default:
891 status = B_FALSE; /* cap not supported */
894 return (status);
897 /* ARGSUSED */
898 static int
899 t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id, uint_t size,
900 const void *val)
902 struct port_info *pi = arg;
903 struct adapter *sc = pi->adapter;
904 struct link_config lc_copy, *lc = &pi->link_cfg;
905 uint8_t v8 = *(uint8_t *)val;
906 uint32_t v32 = *(uint32_t *)val;
907 int old, new = 0, relink = 0, rx_mode = 0, rc = 0;
908 link_flowctrl_t fc;
911 * Save a copy of link_config. This can be used to restore link_config
912 * if t4_link_l1cfg() fails.
914 bcopy(lc, &lc_copy, sizeof (struct link_config));
916 switch (id) {
917 case MAC_PROP_AUTONEG:
918 if (lc->supported & FW_PORT_CAP_ANEG) {
919 old = lc->autoneg;
920 new = v8 ? AUTONEG_ENABLE : AUTONEG_DISABLE;
921 if (old != new) {
922 /* LINTED: E_CONSTANT_CONDITION */
923 lc->autoneg = new;
924 relink = 1;
925 if (new == AUTONEG_DISABLE) {
926 /* Only 100M is available */
927 lc->requested_speed =
928 FW_PORT_CAP_SPEED_100M;
929 lc->advertising =
930 FW_PORT_CAP_SPEED_100M;
931 } else {
933 * Advertise autonegotiation capability
934 * along with supported speeds
936 lc->advertising |= (FW_PORT_CAP_ANEG |
937 (lc->supported &
938 (FW_PORT_CAP_SPEED_100M |
939 FW_PORT_CAP_SPEED_1G)));
940 lc->requested_speed = 0;
943 } else
944 rc = ENOTSUP;
945 break;
947 case MAC_PROP_MTU:
948 if (v32 < 46 || v32 > MAX_MTU) {
949 rc = EINVAL;
950 } else if (v32 != pi->mtu) {
951 pi->mtu = v32;
952 (void) mac_maxsdu_update(pi->mh, v32);
953 rx_mode = 1;
956 break;
958 case MAC_PROP_FLOWCTRL:
959 fc = *(link_flowctrl_t *)val;
960 old = lc->requested_fc & (PAUSE_TX | PAUSE_RX);
962 if (fc == LINK_FLOWCTRL_BI)
963 new = (PAUSE_TX | PAUSE_RX);
964 else if (fc == LINK_FLOWCTRL_TX)
965 new = PAUSE_TX;
966 else if (fc == LINK_FLOWCTRL_RX)
967 new = PAUSE_RX;
969 if (new != old) {
970 lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
971 lc->requested_fc |= new;
972 relink = 1;
974 break;
976 case MAC_PROP_EN_10GFDX_CAP:
977 if (lc->supported & FW_PORT_CAP_ANEG && is_10G_port(pi)) {
978 old = lc->advertising & FW_PORT_CAP_SPEED_10G;
979 new = v8 ? FW_PORT_CAP_SPEED_10G : 0;
980 if (new != old) {
981 lc->advertising &= ~FW_PORT_CAP_SPEED_10G;
982 lc->advertising |= new;
983 relink = 1;
985 } else
986 rc = ENOTSUP;
988 break;
990 case MAC_PROP_EN_1000FDX_CAP:
991 /* Forced 1G */
992 if (lc->autoneg == AUTONEG_ENABLE) {
993 old = lc->advertising & FW_PORT_CAP_SPEED_1G;
994 new = v8 ? FW_PORT_CAP_SPEED_1G : 0;
996 if (old != new) {
997 lc->advertising &= ~FW_PORT_CAP_SPEED_1G;
998 lc->advertising |= new;
999 relink = 1;
1001 } else
1002 rc = ENOTSUP;
1003 break;
1005 case MAC_PROP_EN_100FDX_CAP:
1006 /* Forced 100M */
1007 if (lc->autoneg == AUTONEG_ENABLE) {
1008 old = lc->advertising & FW_PORT_CAP_SPEED_100M;
1009 new = v8 ? FW_PORT_CAP_SPEED_100M : 0;
1010 if (old != new) {
1011 lc->advertising &= ~FW_PORT_CAP_SPEED_100M;
1012 lc->advertising |= new;
1013 relink = 1;
1015 } else
1016 rc = ENOTSUP;
1017 break;
1019 case MAC_PROP_PRIVATE:
1020 rc = setprop(pi, name, val);
1021 break;
1023 default:
1024 rc = ENOTSUP;
1027 if (isset(&sc->open_device_map, pi->port_id) != 0) {
1028 if (relink != 0) {
1029 t4_os_link_changed(pi->adapter, pi->port_id, 0);
1030 rc = begin_synchronized_op(pi, 1, 1);
1031 if (rc != 0)
1032 return (rc);
1033 rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan,
1034 &pi->link_cfg);
1035 end_synchronized_op(pi, 1);
1036 if (rc != 0) {
1037 cxgb_printf(pi->dip, CE_WARN,
1038 "start_link failed:%d", rc);
1040 /* Restore link_config */
1041 bcopy(&lc_copy, lc,
1042 sizeof (struct link_config));
1046 if (rx_mode != 0) {
1047 rc = begin_synchronized_op(pi, 1, 1);
1048 if (rc != 0)
1049 return (rc);
1050 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v32, -1,
1051 -1, -1, -1, false);
1052 end_synchronized_op(pi, 1);
1053 if (rc != 0) {
1054 cxgb_printf(pi->dip, CE_WARN,
1055 "set_rxmode failed: %d", rc);
1060 return (rc);
1063 static int
1064 t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t size,
1065 void *val)
1067 struct port_info *pi = arg;
1068 struct link_config *lc = &pi->link_cfg;
1069 uint8_t *u = val;
1071 switch (id) {
1072 case MAC_PROP_DUPLEX:
1073 *(link_duplex_t *)val = lc->link_ok ? LINK_DUPLEX_FULL :
1074 LINK_DUPLEX_UNKNOWN;
1075 break;
1077 case MAC_PROP_SPEED:
1078 if (lc->link_ok != 0) {
1079 *(uint64_t *)val = lc->speed;
1080 *(uint64_t *)val *= 1000000;
1081 } else
1082 *(uint64_t *)val = 0;
1083 break;
1085 case MAC_PROP_STATUS:
1086 *(link_state_t *)val = lc->link_ok ? LINK_STATE_UP :
1087 LINK_STATE_DOWN;
1088 break;
1090 case MAC_PROP_AUTONEG:
1091 *u = lc->autoneg == AUTONEG_ENABLE;
1092 break;
1094 case MAC_PROP_MTU:
1095 *(uint32_t *)val = pi->mtu;
1096 break;
1098 case MAC_PROP_FLOWCTRL:
1099 if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) ==
1100 (PAUSE_TX | PAUSE_RX))
1101 *(link_flowctrl_t *)val = LINK_FLOWCTRL_BI;
1102 else if (lc->requested_fc & PAUSE_TX)
1103 *(link_flowctrl_t *)val = LINK_FLOWCTRL_TX;
1104 else if (lc->requested_fc & PAUSE_RX)
1105 *(link_flowctrl_t *)val = LINK_FLOWCTRL_RX;
1106 else
1107 *(link_flowctrl_t *)val = LINK_FLOWCTRL_NONE;
1108 break;
1110 case MAC_PROP_ADV_100GFDX_CAP:
1111 case MAC_PROP_EN_100GFDX_CAP:
1112 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_100G);
1113 break;
1115 case MAC_PROP_ADV_40GFDX_CAP:
1116 case MAC_PROP_EN_40GFDX_CAP:
1117 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_40G);
1118 break;
1120 case MAC_PROP_ADV_25GFDX_CAP:
1121 case MAC_PROP_EN_25GFDX_CAP:
1122 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_25G);
1123 break;
1125 case MAC_PROP_ADV_10GFDX_CAP:
1126 case MAC_PROP_EN_10GFDX_CAP:
1127 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_10G);
1128 break;
1130 case MAC_PROP_ADV_1000FDX_CAP:
1131 case MAC_PROP_EN_1000FDX_CAP:
1132 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_1G);
1133 break;
1135 case MAC_PROP_ADV_100FDX_CAP:
1136 case MAC_PROP_EN_100FDX_CAP:
1137 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_100M);
1138 break;
1140 case MAC_PROP_PRIVATE:
1141 return (getprop(pi, name, size, val));
1143 default:
1144 return (ENOTSUP);
1147 return (0);
1150 static void
1151 t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id,
1152 mac_prop_info_handle_t ph)
1154 struct port_info *pi = arg;
1155 struct link_config *lc = &pi->link_cfg;
1157 switch (id) {
1158 case MAC_PROP_DUPLEX:
1159 case MAC_PROP_SPEED:
1160 case MAC_PROP_STATUS:
1161 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1162 break;
1164 case MAC_PROP_AUTONEG:
1165 if (lc->supported & FW_PORT_CAP_ANEG)
1166 mac_prop_info_set_default_uint8(ph, 1);
1167 else
1168 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1169 break;
1171 case MAC_PROP_MTU:
1172 mac_prop_info_set_range_uint32(ph, 46, MAX_MTU);
1173 break;
1175 case MAC_PROP_FLOWCTRL:
1176 mac_prop_info_set_default_link_flowctrl(ph, LINK_FLOWCTRL_BI);
1177 break;
1179 case MAC_PROP_EN_10GFDX_CAP:
1180 if (lc->supported & FW_PORT_CAP_ANEG &&
1181 lc->supported & FW_PORT_CAP_SPEED_10G)
1182 mac_prop_info_set_default_uint8(ph, 1);
1183 else
1184 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1185 break;
1187 case MAC_PROP_EN_1000FDX_CAP:
1188 if (lc->supported & FW_PORT_CAP_ANEG &&
1189 lc->supported & FW_PORT_CAP_SPEED_1G)
1190 mac_prop_info_set_default_uint8(ph, 1);
1191 else
1192 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1193 break;
1195 case MAC_PROP_EN_100FDX_CAP:
1196 if (lc->supported & FW_PORT_CAP_ANEG &&
1197 lc->supported & FW_PORT_CAP_SPEED_100M)
1198 mac_prop_info_set_default_uint8(ph, 1);
1199 else
1200 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1201 break;
1203 case MAC_PROP_ADV_10GFDX_CAP:
1204 case MAC_PROP_ADV_1000FDX_CAP:
1205 case MAC_PROP_ADV_100FDX_CAP:
1206 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
1207 break;
1209 case MAC_PROP_PRIVATE:
1210 propinfo(pi, name, ph);
1211 break;
1213 default:
1214 break;
1218 static int
1219 begin_synchronized_op(struct port_info *pi, int hold, int waitok)
1221 struct adapter *sc = pi->adapter;
1222 int rc = 0;
1224 ADAPTER_LOCK(sc);
1225 while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
1226 if (!waitok) {
1227 rc = EBUSY;
1228 goto failed;
1229 } else if (cv_wait_sig(&sc->cv, &sc->lock) == 0) {
1230 rc = EINTR;
1231 goto failed;
1234 if (IS_DOOMED(pi) != 0) { /* shouldn't happen on Solaris */
1235 rc = ENXIO;
1236 goto failed;
1238 ASSERT(!IS_BUSY(sc));
1239 /* LINTED: E_CONSTANT_CONDITION */
1240 SET_BUSY(sc);
1242 if (!hold)
1243 ADAPTER_UNLOCK(sc);
1245 return (0);
1246 failed:
1247 ADAPTER_UNLOCK(sc);
1248 return (rc);
1251 static void
1252 end_synchronized_op(struct port_info *pi, int held)
1254 struct adapter *sc = pi->adapter;
1256 if (!held)
1257 ADAPTER_LOCK(sc);
1259 ADAPTER_LOCK_ASSERT_OWNED(sc);
1260 ASSERT(IS_BUSY(sc));
1261 /* LINTED: E_CONSTANT_CONDITION */
1262 CLR_BUSY(sc);
1263 cv_signal(&sc->cv);
1264 ADAPTER_UNLOCK(sc);
1267 static int
1268 t4_init_synchronized(struct port_info *pi)
1270 struct adapter *sc = pi->adapter;
1271 int rc = 0;
1273 ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1275 if (isset(&sc->open_device_map, pi->port_id) != 0)
1276 return (0); /* already running */
1278 if (!(sc->flags & FULL_INIT_DONE) &&
1279 ((rc = adapter_full_init(sc)) != 0))
1280 return (rc); /* error message displayed already */
1282 if (!(pi->flags & PORT_INIT_DONE)) {
1283 rc = port_full_init(pi);
1284 if (rc != 0)
1285 return (rc); /* error message displayed already */
1286 } else
1287 enable_port_queues(pi);
1289 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, pi->mtu, 0, 0, 1, 0, false);
1290 if (rc != 0) {
1291 cxgb_printf(pi->dip, CE_WARN, "set_rxmode failed: %d", rc);
1292 goto done;
1294 rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt,
1295 pi->hw_addr, true, true);
1296 if (rc < 0) {
1297 cxgb_printf(pi->dip, CE_WARN, "change_mac failed: %d", rc);
1298 rc = -rc;
1299 goto done;
1300 } else
1301 /* LINTED: E_ASSIGN_NARROW_CONV */
1302 pi->xact_addr_filt = rc;
1304 rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
1305 if (rc != 0) {
1306 cxgb_printf(pi->dip, CE_WARN, "start_link failed: %d", rc);
1307 goto done;
1310 rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true);
1311 if (rc != 0) {
1312 cxgb_printf(pi->dip, CE_WARN, "enable_vi failed: %d", rc);
1313 goto done;
1316 /* all ok */
1317 setbit(&sc->open_device_map, pi->port_id);
1318 done:
1319 if (rc != 0)
1320 (void) t4_uninit_synchronized(pi);
1322 return (rc);
1326 * Idempotent.
1328 static int
1329 t4_uninit_synchronized(struct port_info *pi)
1331 struct adapter *sc = pi->adapter;
1332 int rc;
1334 ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1337 * Disable the VI so that all its data in either direction is discarded
1338 * by the MPS. Leave everything else (the queues, interrupts, and 1Hz
1339 * tick) intact as the TP can deliver negative advice or data that it's
1340 * holding in its RAM (for an offloaded connection) even after the VI is
1341 * disabled.
1343 rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false);
1344 if (rc != 0) {
1345 cxgb_printf(pi->dip, CE_WARN, "disable_vi failed: %d", rc);
1346 return (rc);
1349 disable_port_queues(pi);
1351 clrbit(&sc->open_device_map, pi->port_id);
1353 pi->link_cfg.link_ok = 0;
1354 pi->link_cfg.speed = 0;
1355 mac_link_update(pi->mh, LINK_STATE_UNKNOWN);
1357 return (0);
1360 static void
1361 propinfo(struct port_info *pi, const char *name, mac_prop_info_handle_t ph)
1363 struct adapter *sc = pi->adapter;
1364 struct driver_properties *p = &sc->props;
1365 struct link_config *lc = &pi->link_cfg;
1366 int v;
1367 char str[16];
1369 if (strcmp(name, T4PROP_TMR_IDX) == 0)
1370 v = is_10G_port(pi) ? p->tmr_idx_10g : p->tmr_idx_1g;
1371 else if (strcmp(name, T4PROP_PKTC_IDX) == 0)
1372 v = is_10G_port(pi) ? p->pktc_idx_10g : p->pktc_idx_1g;
1373 else if (strcmp(name, T4PROP_HW_CSUM) == 0)
1374 v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0;
1375 else if (strcmp(name, T4PROP_HW_LSO) == 0)
1376 v = (pi->features & CXGBE_HW_LSO) ? 1 : 0;
1377 else if (strcmp(name, T4PROP_TX_PAUSE) == 0)
1378 v = (lc->fc & PAUSE_TX) ? 1 : 0;
1379 else if (strcmp(name, T4PROP_RX_PAUSE) == 0)
1380 v = (lc->fc & PAUSE_RX) ? 1 : 0;
1381 #if MAC_VERSION == 1
1382 else if (strcmp(name, T4PROP_MTU) == 0)
1383 v = ETHERMTU;
1384 #endif
1385 else
1386 return;
1388 (void) snprintf(str, sizeof (str), "%d", v);
1389 mac_prop_info_set_default_str(ph, str);
1392 static int
1393 getprop(struct port_info *pi, const char *name, uint_t size, void *val)
1395 struct link_config *lc = &pi->link_cfg;
1396 int v;
1398 if (strcmp(name, T4PROP_TMR_IDX) == 0)
1399 v = pi->tmr_idx;
1400 else if (strcmp(name, T4PROP_PKTC_IDX) == 0)
1401 v = pi->pktc_idx;
1402 else if (strcmp(name, T4PROP_HW_CSUM) == 0)
1403 v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0;
1404 else if (strcmp(name, T4PROP_HW_LSO) == 0)
1405 v = (pi->features & CXGBE_HW_LSO) ? 1 : 0;
1406 else if (strcmp(name, T4PROP_TX_PAUSE) == 0)
1407 v = (lc->fc & PAUSE_TX) ? 1 : 0;
1408 else if (strcmp(name, T4PROP_RX_PAUSE) == 0)
1409 v = (lc->fc & PAUSE_RX) ? 1 : 0;
1410 #if MAC_VERSION == 1
1411 else if (strcmp(name, T4PROP_MTU) == 0)
1412 v = pi->mtu;
1413 #endif
1414 else
1415 return (ENOTSUP);
1417 (void) snprintf(val, size, "%d", v);
1418 return (0);
1421 static int
1422 setprop(struct port_info *pi, const char *name, const void *val)
1424 struct adapter *sc = pi->adapter;
1425 long v;
1426 int i, rc = 0, relink = 0, rx_mode = 0;
1427 struct sge_rxq *rxq;
1428 struct link_config lc_old, *lc = &pi->link_cfg;
1431 * Save a copy of link_config. This can be used to restore link_config
1432 * if t4_link_l1cfg() fails.
1434 bcopy(lc, &lc_old, sizeof (struct link_config));
1436 (void) ddi_strtol(val, NULL, 0, &v);
1438 if (strcmp(name, T4PROP_TMR_IDX) == 0) {
1439 if (v < 0 || v >= SGE_NTIMERS)
1440 return (EINVAL);
1441 if (v == pi->tmr_idx)
1442 return (0);
1444 /* LINTED: E_ASSIGN_NARROW_CONV */
1445 pi->tmr_idx = v;
1446 for_each_rxq(pi, i, rxq) {
1447 rxq->iq.intr_params = V_QINTR_TIMER_IDX(v) |
1448 V_QINTR_CNT_EN(pi->pktc_idx >= 0);
1451 } else if (strcmp(name, T4PROP_PKTC_IDX) == 0) {
1452 if (v >= SGE_NCOUNTERS)
1453 return (EINVAL);
1454 if (v == pi->pktc_idx || (v < 0 && pi->pktc_idx == -1))
1455 return (0);
1457 /* LINTED: E_ASSIGN_NARROW_CONV */
1458 pi->pktc_idx = v < 0 ? -1 : v;
1459 for_each_rxq(pi, i, rxq) {
1460 rxq->iq.intr_params = V_QINTR_TIMER_IDX(pi->tmr_idx) |
1461 /* takes effect right away */
1462 V_QINTR_CNT_EN(v >= 0);
1463 /* LINTED: E_ASSIGN_NARROW_CONV */
1464 rxq->iq.intr_pktc_idx = v; /* this needs fresh plumb */
1466 } else if (strcmp(name, T4PROP_HW_CSUM) == 0) {
1467 if (v != 0 && v != 1)
1468 return (EINVAL);
1469 if (v == 1)
1470 pi->features |= CXGBE_HW_CSUM;
1471 else
1472 pi->features &= ~CXGBE_HW_CSUM;
1473 } else if (strcmp(name, T4PROP_HW_LSO) == 0) {
1474 if (v != 0 && v != 1)
1475 return (EINVAL);
1476 if (v == 1)
1477 pi->features |= CXGBE_HW_LSO;
1478 else
1479 pi->features &= ~CXGBE_HW_LSO;
1480 } else if (strcmp(name, T4PROP_TX_PAUSE) == 0) {
1481 if (v != 0 && v != 1)
1482 return (EINVAL);
1484 if (v != 0)
1485 lc->requested_fc |= PAUSE_TX;
1486 else
1487 lc->requested_fc &= ~PAUSE_TX;
1489 relink = 1;
1491 } else if (strcmp(name, T4PROP_RX_PAUSE) == 0) {
1492 if (v != 0 && v != 1)
1493 return (EINVAL);
1495 if (v != 0)
1496 lc->requested_fc |= PAUSE_RX;
1497 else
1498 lc->requested_fc &= ~PAUSE_RX;
1500 relink = 1;
1502 #if MAC_VERSION == 1
1503 else if (strcmp(name, T4PROP_MTU) == 0) {
1504 if (v < 46 || v > MAX_MTU)
1505 return (EINVAL);
1506 if (v == pi->mtu)
1507 return (0);
1509 pi->mtu = (int)v;
1510 (void) mac_maxsdu_update(pi->mh, v);
1511 rx_mode = 1;
1513 #endif
1514 else
1515 return (ENOTSUP);
1517 if (!(relink || rx_mode))
1518 return (0);
1520 /* If we are here, either relink or rx_mode is 1 */
1521 if (isset(&sc->open_device_map, pi->port_id) != 0) {
1522 if (relink != 0) {
1523 rc = begin_synchronized_op(pi, 1, 1);
1524 if (rc != 0)
1525 return (rc);
1526 rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc);
1527 end_synchronized_op(pi, 1);
1528 if (rc != 0) {
1529 cxgb_printf(pi->dip, CE_WARN,
1530 "start_link failed:%d", rc);
1531 /* Restore link_config */
1532 bcopy(&lc_old, lc, sizeof (struct link_config));
1534 } else if (rx_mode != 0) {
1535 rc = begin_synchronized_op(pi, 1, 1);
1536 if (rc != 0)
1537 return (rc);
1538 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v, -1, -1,
1539 -1, -1, false);
1540 end_synchronized_op(pi, 1);
1541 if (rc != 0) {
1542 cxgb_printf(pi->dip, CE_WARN,
1543 "set_rxmode failed: %d", rc);
1546 return (rc);
1549 return (0);
1552 void
1553 t4_mc_init(struct port_info *pi)
1555 pi->props = t4_priv_props;
1558 void
1559 t4_mc_cb_init(struct port_info *pi)
1561 if (pi->adapter->props.multi_rings)
1562 pi->mc = &t4_m_ring_callbacks;
1563 else
1564 pi->mc = &t4_m_callbacks;
1567 void
1568 t4_os_link_changed(struct adapter *sc, int idx, int link_stat)
1570 struct port_info *pi = sc->port[idx];
1572 mac_link_update(pi->mh, link_stat ? LINK_STATE_UP : LINK_STATE_DOWN);
1575 /* ARGSUSED */
1576 void
1577 t4_mac_rx(struct port_info *pi, struct sge_rxq *rxq, mblk_t *m)
1579 mac_rx(pi->mh, NULL, m);
1582 void
1583 t4_mac_tx_update(struct port_info *pi, struct sge_txq *txq)
1585 if (pi->adapter->props.multi_rings)
1586 mac_tx_ring_update(pi->mh, txq->ring_handle);
1587 else
1588 mac_tx_update(pi->mh);