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 mblk_t *t4_mc_tx(void *arg, mblk_t *m);
41 static boolean_t t4_mc_getcapab(void *arg, mac_capab_t cap, void *data);
42 static int t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id,
43 uint_t size, const void *val);
44 static int t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id,
45 uint_t size, void *val);
46 static void t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id,
47 mac_prop_info_handle_t ph);
48
49 static int begin_synchronized_op(struct port_info *pi, int hold, int waitok);
50 static void end_synchronized_op(struct port_info *pi, int held);
51 static int t4_init_synchronized(struct port_info *pi);
52 static int t4_uninit_synchronized(struct port_info *pi);
53 static void propinfo(struct port_info *pi, const char *name,
54 mac_prop_info_handle_t ph);
55 static int getprop(struct port_info *pi, const char *name, uint_t size,
56 void *val);
57 static int setprop(struct port_info *pi, const char *name, const void *val);
58
59 mac_callbacks_t t4_m_callbacks = {
60 .mc_callbacks = MC_GETCAPAB | MC_PROPERTIES,
61 .mc_getstat = t4_mc_getstat,
62 .mc_start = t4_mc_start,
63 .mc_stop = t4_mc_stop,
64 .mc_setpromisc = t4_mc_setpromisc,
65 .mc_multicst = t4_mc_multicst,
66 .mc_unicst = t4_mc_unicst,
67 .mc_tx = t4_mc_tx,
68 .mc_getcapab = t4_mc_getcapab,
69 .mc_setprop = t4_mc_setprop,
70 .mc_getprop = t4_mc_getprop,
71 .mc_propinfo = t4_mc_propinfo,
72 };
73
74 #define T4PROP_TMR_IDX "_holdoff_timer_idx"
75 #define T4PROP_PKTC_IDX "_holdoff_pktc_idx"
76 #define T4PROP_MTU "_mtu"
77 #define T4PROP_HW_CSUM "_hw_csum"
78 #define T4PROP_HW_LSO "_hw_lso"
79 #define T4PROP_TX_PAUSE "_tx_pause"
80 #define T4PROP_RX_PAUSE "_rx_pause"
81
82 char *t4_priv_props[] = {
83 T4PROP_TMR_IDX,
84 T4PROP_PKTC_IDX,
85 #if MAC_VERSION == 1
86 /* MAC_VERSION 1 doesn't seem to use MAC_PROP_MTU, hmmmm */
87 T4PROP_MTU,
88 #endif
89 T4PROP_HW_CSUM,
90 T4PROP_HW_LSO,
91 T4PROP_TX_PAUSE,
92 T4PROP_RX_PAUSE,
93 NULL
94 };
95
96 static int
t4_mc_getstat(void * arg,uint_t stat,uint64_t * val)97 t4_mc_getstat(void *arg, uint_t stat, uint64_t *val)
98 {
99 struct port_info *pi = arg;
100 struct adapter *sc = pi->adapter;
101 struct link_config *lc = &pi->link_cfg;
102
103 #define GET_STAT(name) \
104 t4_read_reg64(sc, PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_##name##_L))
105
106 switch (stat) {
107 case MAC_STAT_IFSPEED:
108 if (lc->link_ok != 0) {
109 *val = lc->speed;
110 *val *= 1000000;
111 } else
112 *val = 0;
113 break;
114
115 case MAC_STAT_MULTIRCV:
116 *val = GET_STAT(RX_PORT_MCAST);
117 break;
118
119 case MAC_STAT_BRDCSTRCV:
120 *val = GET_STAT(RX_PORT_BCAST);
121 break;
122
123 case MAC_STAT_MULTIXMT:
124 *val = GET_STAT(TX_PORT_MCAST);
125 break;
126
127 case MAC_STAT_BRDCSTXMT:
128 *val = GET_STAT(TX_PORT_BCAST);
129 break;
130
131 case MAC_STAT_NORCVBUF:
132 *val = 0; /* TODO should come from rxq->nomem */
133 break;
134
135 case MAC_STAT_IERRORS:
136 *val = GET_STAT(RX_PORT_MTU_ERROR) +
137 GET_STAT(RX_PORT_MTU_CRC_ERROR) +
138 GET_STAT(RX_PORT_CRC_ERROR) +
139 GET_STAT(RX_PORT_LEN_ERROR) +
140 GET_STAT(RX_PORT_SYM_ERROR) +
141 GET_STAT(RX_PORT_LESS_64B);
142 break;
143
144 case MAC_STAT_UNKNOWNS:
145 return (ENOTSUP);
146
147 case MAC_STAT_NOXMTBUF:
148 *val = GET_STAT(TX_PORT_DROP);
149 break;
150
151 case MAC_STAT_OERRORS:
152 *val = GET_STAT(TX_PORT_ERROR);
153 break;
154
155 case MAC_STAT_COLLISIONS:
156 return (ENOTSUP);
157
158 case MAC_STAT_RBYTES:
159 *val = GET_STAT(RX_PORT_BYTES);
160 break;
161
162 case MAC_STAT_IPACKETS:
163 *val = GET_STAT(RX_PORT_FRAMES);
164 break;
165
166 case MAC_STAT_OBYTES:
167 *val = GET_STAT(TX_PORT_BYTES);
168 break;
169
170 case MAC_STAT_OPACKETS:
171 *val = GET_STAT(TX_PORT_FRAMES);
172 break;
173
174 case ETHER_STAT_ALIGN_ERRORS:
175 return (ENOTSUP);
176
177 case ETHER_STAT_FCS_ERRORS:
178 *val = GET_STAT(RX_PORT_CRC_ERROR);
179 break;
180
181 case ETHER_STAT_FIRST_COLLISIONS:
182 case ETHER_STAT_MULTI_COLLISIONS:
183 case ETHER_STAT_SQE_ERRORS:
184 case ETHER_STAT_DEFER_XMTS:
185 case ETHER_STAT_TX_LATE_COLLISIONS:
186 case ETHER_STAT_EX_COLLISIONS:
187 return (ENOTSUP);
188
189 case ETHER_STAT_MACXMT_ERRORS:
190 *val = GET_STAT(TX_PORT_ERROR);
191 break;
192
193 case ETHER_STAT_CARRIER_ERRORS:
194 return (ENOTSUP);
195
196 case ETHER_STAT_TOOLONG_ERRORS:
197 *val = GET_STAT(RX_PORT_MTU_ERROR);
198 break;
199
200 case ETHER_STAT_MACRCV_ERRORS:
201 *val = GET_STAT(RX_PORT_MTU_ERROR) +
202 GET_STAT(RX_PORT_MTU_CRC_ERROR) +
203 GET_STAT(RX_PORT_CRC_ERROR) +
204 GET_STAT(RX_PORT_LEN_ERROR) +
205 GET_STAT(RX_PORT_SYM_ERROR) +
206 GET_STAT(RX_PORT_LESS_64B);
207 break;
208
209 case ETHER_STAT_XCVR_ADDR:
210 case ETHER_STAT_XCVR_ID:
211 case ETHER_STAT_XCVR_INUSE:
212 return (ENOTSUP);
213
214 case ETHER_STAT_CAP_1000FDX:
215 *val = !!(lc->supported & FW_PORT_CAP_SPEED_1G);
216 break;
217
218 case ETHER_STAT_CAP_1000HDX:
219 return (ENOTSUP);
220
221 case ETHER_STAT_CAP_100FDX:
222 *val = !!(lc->supported & FW_PORT_CAP_SPEED_100M);
223 break;
224
225 case ETHER_STAT_CAP_100HDX:
226 return (ENOTSUP);
227
228 case ETHER_STAT_CAP_10FDX:
229 case ETHER_STAT_CAP_10HDX:
230 return (ENOTSUP);
231
232 case ETHER_STAT_CAP_ASMPAUSE:
233 *val = 0;
234 break;
235
236 case ETHER_STAT_CAP_PAUSE:
237 *val = 1;
238 break;
239
240 case ETHER_STAT_CAP_AUTONEG:
241 *val = !!(lc->supported & FW_PORT_CAP_ANEG);
242 break;
243
244 /*
245 * We have set flow control configuration based on tx_pause and rx_pause
246 * values supported through ndd. Now, we need to translate the settings
247 * we have in link_config structure to adv_cap_asmpause and
248 * adv_cap_pause.
249 *
250 * There are 4 combinations possible and the translation is as below:
251 * tx_pause = 0 => We don't send pause frames during Rx congestion
252 * tx_pause = 1 => We send pause frames during Rx congestion
253 * rx_pause = 0 => We ignore received pause frames
254 * rx_pause = 1 => We pause transmission when we receive pause frames
255 *
256 * +----------------------------+----------------------------------+
257 * | tx_pause | rx_pause | adv_cap_asmpause | adv_cap_pause |
258 * +-------------------------+-------------------------------------+
259 * | 0 | 0 | 0 | 0 |
260 * | 0 | 1 | 1 | 0 |
261 * | 1 | 0 | 1 | 1 |
262 * | 1 | 1 | 0 | 1 |
263 * +----------------------------+----------------------------------+
264 */
265
266 /* Advertised asymmetric pause capability */
267 case ETHER_STAT_ADV_CAP_ASMPAUSE:
268 *val = (((lc->requested_fc & PAUSE_TX) ? 1 : 0) ^
269 (lc->requested_fc & PAUSE_RX));
270 break;
271
272 /* Advertised pause capability */
273 case ETHER_STAT_ADV_CAP_PAUSE:
274 *val = (lc->requested_fc & PAUSE_TX) ? 1 : 0;
275 break;
276
277 case ETHER_STAT_ADV_CAP_1000FDX:
278 case ETHER_STAT_ADV_CAP_1000HDX:
279 case ETHER_STAT_ADV_CAP_100FDX:
280 case ETHER_STAT_ADV_CAP_100HDX:
281 case ETHER_STAT_ADV_CAP_10FDX:
282 case ETHER_STAT_ADV_CAP_10HDX:
283 case ETHER_STAT_ADV_CAP_AUTONEG:
284 return (ENOTSUP); /* TODO */
285
286 case ETHER_STAT_LP_CAP_1000FDX:
287 case ETHER_STAT_LP_CAP_1000HDX:
288 case ETHER_STAT_LP_CAP_100FDX:
289 case ETHER_STAT_LP_CAP_100HDX:
290 case ETHER_STAT_LP_CAP_10FDX:
291 case ETHER_STAT_LP_CAP_10HDX:
292 case ETHER_STAT_LP_CAP_ASMPAUSE:
293 case ETHER_STAT_LP_CAP_PAUSE:
294 case ETHER_STAT_LP_CAP_AUTONEG:
295 return (ENOTSUP);
296
297 case ETHER_STAT_LINK_ASMPAUSE:
298 *val = 0;
299 break;
300
301 case ETHER_STAT_LINK_PAUSE:
302 *val = 1;
303 break;
304
305 case ETHER_STAT_LINK_AUTONEG:
306 *val = lc->autoneg == AUTONEG_ENABLE;
307 break;
308
309 case ETHER_STAT_LINK_DUPLEX:
310 if (lc->link_ok != 0)
311 *val = LINK_DUPLEX_FULL;
312 else
313 *val = LINK_DUPLEX_UNKNOWN;
314 break;
315
316 default:
317 #ifdef DEBUG
318 cxgb_printf(pi->dip, CE_NOTE, "stat %d not implemented.", stat);
319 #endif
320 return (ENOTSUP);
321 }
322 #undef GET_STAT
323
324 return (0);
325 }
326
327 static int
t4_mc_start(void * arg)328 t4_mc_start(void *arg)
329 {
330 struct port_info *pi = arg;
331 int rc;
332
333 rc = begin_synchronized_op(pi, 0, 1);
334 if (rc != 0)
335 return (rc);
336 rc = t4_init_synchronized(pi);
337 end_synchronized_op(pi, 0);
338
339 return (rc);
340 }
341
342 static void
t4_mc_stop(void * arg)343 t4_mc_stop(void *arg)
344 {
345 struct port_info *pi = arg;
346
347 while (begin_synchronized_op(pi, 0, 1) != 0)
348 continue;
349 (void) t4_uninit_synchronized(pi);
350 end_synchronized_op(pi, 0);
351 }
352
353 static int
t4_mc_setpromisc(void * arg,boolean_t on)354 t4_mc_setpromisc(void *arg, boolean_t on)
355 {
356 struct port_info *pi = arg;
357 struct adapter *sc = pi->adapter;
358 int rc;
359
360 rc = begin_synchronized_op(pi, 1, 1);
361 if (rc != 0)
362 return (rc);
363 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, -1, on ? 1 : 0, -1, -1, -1,
364 false);
365 end_synchronized_op(pi, 1);
366
367 return (rc);
368 }
369
370 /*
371 * TODO: Starts failing as soon as the 336 entry table fills up. Need to use
372 * hash in that case.
373 */
374 static int
t4_mc_multicst(void * arg,boolean_t add,const uint8_t * mcaddr)375 t4_mc_multicst(void *arg, boolean_t add, const uint8_t *mcaddr)
376 {
377 struct port_info *pi = arg;
378 struct adapter *sc = pi->adapter;
379 struct fw_vi_mac_cmd c;
380 int len16, rc;
381
382 len16 = howmany(sizeof (c.op_to_viid) + sizeof (c.freemacs_to_len16) +
383 sizeof (c.u.exact[0]), 16);
384 c.op_to_viid = htonl(V_FW_CMD_OP(FW_VI_MAC_CMD) | F_FW_CMD_REQUEST |
385 F_FW_CMD_WRITE | V_FW_VI_MAC_CMD_VIID(pi->viid));
386 c.freemacs_to_len16 = htonl(V_FW_CMD_LEN16(len16));
387 c.u.exact[0].valid_to_idx = htons(F_FW_VI_MAC_CMD_VALID |
388 V_FW_VI_MAC_CMD_IDX(add ? FW_VI_MAC_ADD_MAC :
389 FW_VI_MAC_MAC_BASED_FREE));
390 bcopy(mcaddr, &c.u.exact[0].macaddr, ETHERADDRL);
391
392 rc = begin_synchronized_op(pi, 1, 1);
393 if (rc != 0)
394 return (rc);
395 rc = -t4_wr_mbox_meat(sc, sc->mbox, &c, len16 * 16, &c, true);
396 end_synchronized_op(pi, 1);
397 if (rc != 0)
398 return (rc);
399 #ifdef DEBUG
400 /*
401 * TODO: Firmware doesn't seem to return the correct index on removal
402 * (it gives back 0x3fd FW_VI_MAC_MAC_BASED_FREE unchanged. Remove this
403 * code once it is fixed.
404 */
405 else {
406 uint16_t idx;
407
408 idx = G_FW_VI_MAC_CMD_IDX(ntohs(c.u.exact[0].valid_to_idx));
409 cxgb_printf(pi->dip, CE_NOTE,
410 "%02x:%02x:%02x:%02x:%02x:%02x %s %d", mcaddr[0],
411 mcaddr[1], mcaddr[2], mcaddr[3], mcaddr[4], mcaddr[5],
412 add ? "added at index" : "removed from index", idx);
413 }
414 #endif
415
416 return (0);
417 }
418
419 static int
t4_mc_unicst(void * arg,const uint8_t * ucaddr)420 t4_mc_unicst(void *arg, const uint8_t *ucaddr)
421 {
422 struct port_info *pi = arg;
423 struct adapter *sc = pi->adapter;
424 int rc;
425
426 rc = begin_synchronized_op(pi, 1, 1);
427 if (rc != 0)
428 return (rc);
429 rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, ucaddr,
430 true, true);
431 if (rc < 0)
432 rc = -rc;
433 else {
434 /* LINTED: E_CONSTANT_CONDITION */
435 pi->xact_addr_filt = rc;
436 rc = 0;
437 }
438 end_synchronized_op(pi, 1);
439
440 return (rc);
441 }
442
443 static mblk_t *
t4_mc_tx(void * arg,mblk_t * m)444 t4_mc_tx(void *arg, mblk_t *m)
445 {
446 struct port_info *pi = arg;
447 struct adapter *sc = pi->adapter;
448 struct sge_txq *txq = &sc->sge.txq[pi->first_txq];
449
450 return (t4_eth_tx(pi, txq, m));
451 }
452
453 static boolean_t
t4_mc_getcapab(void * arg,mac_capab_t cap,void * data)454 t4_mc_getcapab(void *arg, mac_capab_t cap, void *data)
455 {
456 struct port_info *pi = arg;
457 boolean_t status = B_TRUE;
458
459 switch (cap) {
460 case MAC_CAPAB_HCKSUM:
461 if (pi->features & CXGBE_HW_CSUM) {
462 uint32_t *d = data;
463 *d = HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM;
464 } else
465 status = B_FALSE;
466 break;
467
468 case MAC_CAPAB_LSO:
469 /* Enabling LSO requires Checksum offloading */
470 if (pi->features & CXGBE_HW_LSO &&
471 pi->features & CXGBE_HW_CSUM) {
472 mac_capab_lso_t *d = data;
473
474 d->lso_flags = LSO_TX_BASIC_TCP_IPV4;
475 d->lso_basic_tcp_ipv4.lso_max = 65535;
476 } else
477 status = B_FALSE;
478 break;
479
480 default:
481 status = B_FALSE; /* cap not supported */
482 }
483
484 return (status);
485 }
486
487 /* ARGSUSED */
488 static int
t4_mc_setprop(void * arg,const char * name,mac_prop_id_t id,uint_t size,const void * val)489 t4_mc_setprop(void *arg, const char *name, mac_prop_id_t id, uint_t size,
490 const void *val)
491 {
492 struct port_info *pi = arg;
493 struct adapter *sc = pi->adapter;
494 struct link_config lc_copy, *lc = &pi->link_cfg;
495 uint8_t v8 = *(uint8_t *)val;
496 uint32_t v32 = *(uint32_t *)val;
497 int old, new = 0, relink = 0, rx_mode = 0, rc = 0;
498 link_flowctrl_t fc;
499
500 /*
501 * Save a copy of link_config. This can be used to restore link_config
502 * if t4_link_start() fails.
503 */
504 bcopy(lc, &lc_copy, sizeof (struct link_config));
505
506 switch (id) {
507 case MAC_PROP_AUTONEG:
508 if (lc->supported & FW_PORT_CAP_ANEG) {
509 old = lc->autoneg;
510 new = v8 ? AUTONEG_ENABLE : AUTONEG_DISABLE;
511 if (old != new) {
512 /* LINTED: E_CONSTANT_CONDITION */
513 lc->autoneg = new;
514 relink = 1;
515 if (new == AUTONEG_DISABLE) {
516 /* Only 100M is available */
517 lc->requested_speed =
518 FW_PORT_CAP_SPEED_100M;
519 lc->advertising =
520 FW_PORT_CAP_SPEED_100M;
521 } else {
522 /*
523 * Advertise autonegotiation capability
524 * along with supported speeds
525 */
526 lc->advertising |= (FW_PORT_CAP_ANEG |
527 (lc->supported &
528 (FW_PORT_CAP_SPEED_100M |
529 FW_PORT_CAP_SPEED_1G)));
530 lc->requested_speed = 0;
531 }
532 }
533 } else
534 rc = ENOTSUP;
535 break;
536
537 case MAC_PROP_MTU:
538 if (v32 < 46 || v32 > MAX_MTU) {
539 rc = EINVAL;
540 } else if (v32 != pi->mtu) {
541 pi->mtu = v32;
542 (void) mac_maxsdu_update(pi->mh, v32);
543 rx_mode = 1;
544 }
545
546 break;
547
548 case MAC_PROP_FLOWCTRL:
549 fc = *(link_flowctrl_t *)val;
550 old = lc->requested_fc & (PAUSE_TX | PAUSE_RX);
551
552 if (fc == LINK_FLOWCTRL_BI)
553 new = (PAUSE_TX | PAUSE_RX);
554 else if (fc == LINK_FLOWCTRL_TX)
555 new = PAUSE_TX;
556 else if (fc == LINK_FLOWCTRL_RX)
557 new = PAUSE_RX;
558
559 if (new != old) {
560 lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX);
561 lc->requested_fc |= new;
562 relink = 1;
563 }
564 break;
565
566 case MAC_PROP_EN_10GFDX_CAP:
567 if (lc->supported & FW_PORT_CAP_ANEG && is_10G_port(pi)) {
568 old = lc->advertising & FW_PORT_CAP_SPEED_10G;
569 new = v8 ? FW_PORT_CAP_SPEED_10G : 0;
570 if (new != old) {
571 lc->advertising &= ~FW_PORT_CAP_SPEED_10G;
572 lc->advertising |= new;
573 relink = 1;
574 }
575 } else
576 rc = ENOTSUP;
577
578 break;
579
580 case MAC_PROP_EN_1000FDX_CAP:
581 /* Forced 1G */
582 if (lc->autoneg == AUTONEG_ENABLE) {
583 old = lc->advertising & FW_PORT_CAP_SPEED_1G;
584 new = v8 ? FW_PORT_CAP_SPEED_1G : 0;
585
586 if (old != new) {
587 lc->advertising &= ~FW_PORT_CAP_SPEED_1G;
588 lc->advertising |= new;
589 relink = 1;
590 }
591 } else
592 rc = ENOTSUP;
593 break;
594
595 case MAC_PROP_EN_100FDX_CAP:
596 /* Forced 100M */
597 if (lc->autoneg == AUTONEG_ENABLE) {
598 old = lc->advertising & FW_PORT_CAP_SPEED_100M;
599 new = v8 ? FW_PORT_CAP_SPEED_100M : 0;
600 if (old != new) {
601 lc->advertising &= ~FW_PORT_CAP_SPEED_100M;
602 lc->advertising |= new;
603 relink = 1;
604 }
605 } else
606 rc = ENOTSUP;
607 break;
608
609 case MAC_PROP_PRIVATE:
610 rc = setprop(pi, name, val);
611 break;
612
613 default:
614 rc = ENOTSUP;
615 }
616
617 if (isset(&sc->open_device_map, pi->port_id) != 0) {
618 if (relink != 0) {
619 t4_os_link_changed(pi->adapter, pi->port_id, 0);
620 rc = begin_synchronized_op(pi, 1, 1);
621 if (rc != 0)
622 return (rc);
623 rc = -t4_link_start(sc, sc->mbox, pi->tx_chan,
624 &pi->link_cfg);
625 end_synchronized_op(pi, 1);
626 if (rc != 0) {
627 cxgb_printf(pi->dip, CE_WARN,
628 "start_link failed:%d", rc);
629
630 /* Restore link_config */
631 bcopy(&lc_copy, lc,
632 sizeof (struct link_config));
633 }
634 }
635
636 if (rx_mode != 0) {
637 rc = begin_synchronized_op(pi, 1, 1);
638 if (rc != 0)
639 return (rc);
640 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v32, -1,
641 -1, -1, -1, false);
642 end_synchronized_op(pi, 1);
643 if (rc != 0) {
644 cxgb_printf(pi->dip, CE_WARN,
645 "set_rxmode failed: %d", rc);
646 }
647 }
648 }
649
650 return (rc);
651 }
652
653 static int
t4_mc_getprop(void * arg,const char * name,mac_prop_id_t id,uint_t size,void * val)654 t4_mc_getprop(void *arg, const char *name, mac_prop_id_t id, uint_t size,
655 void *val)
656 {
657 struct port_info *pi = arg;
658 struct link_config *lc = &pi->link_cfg;
659 uint8_t *u = val;
660
661 switch (id) {
662 case MAC_PROP_DUPLEX:
663 *(link_duplex_t *)val = lc->link_ok ? LINK_DUPLEX_FULL :
664 LINK_DUPLEX_UNKNOWN;
665 break;
666
667 case MAC_PROP_SPEED:
668 if (lc->link_ok != 0) {
669 *(uint64_t *)val = lc->speed;
670 *(uint64_t *)val *= 1000000;
671 } else
672 *(uint64_t *)val = 0;
673 break;
674
675 case MAC_PROP_STATUS:
676 *(link_state_t *)val = lc->link_ok ? LINK_STATE_UP :
677 LINK_STATE_DOWN;
678 break;
679
680 case MAC_PROP_AUTONEG:
681 *u = lc->autoneg == AUTONEG_ENABLE;
682 break;
683
684 case MAC_PROP_MTU:
685 *(uint32_t *)val = pi->mtu;
686 break;
687
688 case MAC_PROP_FLOWCTRL:
689 if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) ==
690 (PAUSE_TX | PAUSE_RX))
691 *(link_flowctrl_t *)val = LINK_FLOWCTRL_BI;
692 else if (lc->requested_fc & PAUSE_TX)
693 *(link_flowctrl_t *)val = LINK_FLOWCTRL_TX;
694 else if (lc->requested_fc & PAUSE_RX)
695 *(link_flowctrl_t *)val = LINK_FLOWCTRL_RX;
696 else
697 *(link_flowctrl_t *)val = LINK_FLOWCTRL_NONE;
698 break;
699
700 case MAC_PROP_ADV_10GFDX_CAP:
701 case MAC_PROP_EN_10GFDX_CAP:
702 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_10G);
703 break;
704
705 case MAC_PROP_ADV_1000FDX_CAP:
706 case MAC_PROP_EN_1000FDX_CAP:
707 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_1G);
708 break;
709
710 case MAC_PROP_ADV_100FDX_CAP:
711 case MAC_PROP_EN_100FDX_CAP:
712 *u = !!(lc->advertising & FW_PORT_CAP_SPEED_100M);
713 break;
714
715 case MAC_PROP_PRIVATE:
716 return (getprop(pi, name, size, val));
717
718 default:
719 return (ENOTSUP);
720 }
721
722 return (0);
723 }
724
725 static void
t4_mc_propinfo(void * arg,const char * name,mac_prop_id_t id,mac_prop_info_handle_t ph)726 t4_mc_propinfo(void *arg, const char *name, mac_prop_id_t id,
727 mac_prop_info_handle_t ph)
728 {
729 struct port_info *pi = arg;
730 struct link_config *lc = &pi->link_cfg;
731
732 switch (id) {
733 case MAC_PROP_DUPLEX:
734 case MAC_PROP_SPEED:
735 case MAC_PROP_STATUS:
736 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
737 break;
738
739 case MAC_PROP_AUTONEG:
740 if (lc->supported & FW_PORT_CAP_ANEG)
741 mac_prop_info_set_default_uint8(ph, 1);
742 else
743 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
744 break;
745
746 case MAC_PROP_MTU:
747 mac_prop_info_set_range_uint32(ph, 46, MAX_MTU);
748 break;
749
750 case MAC_PROP_FLOWCTRL:
751 mac_prop_info_set_default_link_flowctrl(ph, LINK_FLOWCTRL_BI);
752 break;
753
754 case MAC_PROP_EN_10GFDX_CAP:
755 if (lc->supported & FW_PORT_CAP_ANEG &&
756 lc->supported & FW_PORT_CAP_SPEED_10G)
757 mac_prop_info_set_default_uint8(ph, 1);
758 else
759 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
760 break;
761
762 case MAC_PROP_EN_1000FDX_CAP:
763 if (lc->supported & FW_PORT_CAP_ANEG &&
764 lc->supported & FW_PORT_CAP_SPEED_1G)
765 mac_prop_info_set_default_uint8(ph, 1);
766 else
767 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
768 break;
769
770 case MAC_PROP_EN_100FDX_CAP:
771 if (lc->supported & FW_PORT_CAP_ANEG &&
772 lc->supported & FW_PORT_CAP_SPEED_100M)
773 mac_prop_info_set_default_uint8(ph, 1);
774 else
775 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
776 break;
777
778 case MAC_PROP_ADV_10GFDX_CAP:
779 case MAC_PROP_ADV_1000FDX_CAP:
780 case MAC_PROP_ADV_100FDX_CAP:
781 mac_prop_info_set_perm(ph, MAC_PROP_PERM_READ);
782 break;
783
784 case MAC_PROP_PRIVATE:
785 propinfo(pi, name, ph);
786 break;
787
788 default:
789 break;
790 }
791 }
792
793 static int
begin_synchronized_op(struct port_info * pi,int hold,int waitok)794 begin_synchronized_op(struct port_info *pi, int hold, int waitok)
795 {
796 struct adapter *sc = pi->adapter;
797 int rc = 0;
798
799 ADAPTER_LOCK(sc);
800 while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
801 if (!waitok) {
802 rc = EBUSY;
803 goto failed;
804 } else if (cv_wait_sig(&sc->cv, &sc->lock) == 0) {
805 rc = EINTR;
806 goto failed;
807 }
808 }
809 if (IS_DOOMED(pi) != 0) { /* shouldn't happen on Solaris */
810 rc = ENXIO;
811 goto failed;
812 }
813 ASSERT(!IS_BUSY(sc));
814 /* LINTED: E_CONSTANT_CONDITION */
815 SET_BUSY(sc);
816
817 if (!hold)
818 ADAPTER_UNLOCK(sc);
819
820 return (0);
821 failed:
822 ADAPTER_UNLOCK(sc);
823 return (rc);
824 }
825
826 static void
end_synchronized_op(struct port_info * pi,int held)827 end_synchronized_op(struct port_info *pi, int held)
828 {
829 struct adapter *sc = pi->adapter;
830
831 if (!held)
832 ADAPTER_LOCK(sc);
833
834 ADAPTER_LOCK_ASSERT_OWNED(sc);
835 ASSERT(IS_BUSY(sc));
836 /* LINTED: E_CONSTANT_CONDITION */
837 CLR_BUSY(sc);
838 cv_signal(&sc->cv);
839 ADAPTER_UNLOCK(sc);
840 }
841
842 static int
t4_init_synchronized(struct port_info * pi)843 t4_init_synchronized(struct port_info *pi)
844 {
845 struct adapter *sc = pi->adapter;
846 int rc = 0;
847
848 ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
849
850 if (isset(&sc->open_device_map, pi->port_id) != 0)
851 return (0); /* already running */
852
853 if (!(sc->flags & FULL_INIT_DONE) &&
854 ((rc = adapter_full_init(sc)) != 0))
855 return (rc); /* error message displayed already */
856
857 if (!(pi->flags & PORT_INIT_DONE)) {
858 rc = port_full_init(pi);
859 if (rc != 0)
860 return (rc); /* error message displayed already */
861 } else
862 enable_port_queues(pi);
863
864 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, pi->mtu, 0, 0, 1, 0, false);
865 if (rc != 0) {
866 cxgb_printf(pi->dip, CE_WARN, "set_rxmode failed: %d", rc);
867 goto done;
868 }
869 rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt,
870 pi->hw_addr, true, true);
871 if (rc < 0) {
872 cxgb_printf(pi->dip, CE_WARN, "change_mac failed: %d", rc);
873 rc = -rc;
874 goto done;
875 } else
876 /* LINTED: E_ASSIGN_NARROW_CONV */
877 pi->xact_addr_filt = rc;
878
879 rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
880 if (rc != 0) {
881 cxgb_printf(pi->dip, CE_WARN, "start_link failed: %d", rc);
882 goto done;
883 }
884
885 rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true);
886 if (rc != 0) {
887 cxgb_printf(pi->dip, CE_WARN, "enable_vi failed: %d", rc);
888 goto done;
889 }
890
891 /* all ok */
892 setbit(&sc->open_device_map, pi->port_id);
893 done:
894 if (rc != 0)
895 (void) t4_uninit_synchronized(pi);
896
897 return (rc);
898 }
899
900 /*
901 * Idempotent.
902 */
903 static int
t4_uninit_synchronized(struct port_info * pi)904 t4_uninit_synchronized(struct port_info *pi)
905 {
906 struct adapter *sc = pi->adapter;
907 int rc;
908
909 ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
910
911 /*
912 * Disable the VI so that all its data in either direction is discarded
913 * by the MPS. Leave everything else (the queues, interrupts, and 1Hz
914 * tick) intact as the TP can deliver negative advice or data that it's
915 * holding in its RAM (for an offloaded connection) even after the VI is
916 * disabled.
917 */
918 rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false);
919 if (rc != 0) {
920 cxgb_printf(pi->dip, CE_WARN, "disable_vi failed: %d", rc);
921 return (rc);
922 }
923
924 disable_port_queues(pi);
925
926 clrbit(&sc->open_device_map, pi->port_id);
927
928 pi->link_cfg.link_ok = 0;
929 pi->link_cfg.speed = 0;
930 mac_link_update(pi->mh, LINK_STATE_UNKNOWN);
931
932 return (0);
933 }
934
935 static void
propinfo(struct port_info * pi,const char * name,mac_prop_info_handle_t ph)936 propinfo(struct port_info *pi, const char *name, mac_prop_info_handle_t ph)
937 {
938 struct adapter *sc = pi->adapter;
939 struct driver_properties *p = &sc->props;
940 struct link_config *lc = &pi->link_cfg;
941 int v;
942 char str[16];
943
944 if (strcmp(name, T4PROP_TMR_IDX) == 0)
945 v = is_10G_port(pi) ? p->tmr_idx_10g : p->tmr_idx_1g;
946 else if (strcmp(name, T4PROP_PKTC_IDX) == 0)
947 v = is_10G_port(pi) ? p->pktc_idx_10g : p->pktc_idx_1g;
948 else if (strcmp(name, T4PROP_HW_CSUM) == 0)
949 v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0;
950 else if (strcmp(name, T4PROP_HW_LSO) == 0)
951 v = (pi->features & CXGBE_HW_LSO) ? 1 : 0;
952 else if (strcmp(name, T4PROP_TX_PAUSE) == 0)
953 v = (lc->fc & PAUSE_TX) ? 1 : 0;
954 else if (strcmp(name, T4PROP_RX_PAUSE) == 0)
955 v = (lc->fc & PAUSE_RX) ? 1 : 0;
956 #if MAC_VERSION == 1
957 else if (strcmp(name, T4PROP_MTU) == 0)
958 v = ETHERMTU;
959 #endif
960 else
961 return;
962
963 (void) snprintf(str, sizeof (str), "%d", v);
964 mac_prop_info_set_default_str(ph, str);
965 }
966
967 static int
getprop(struct port_info * pi,const char * name,uint_t size,void * val)968 getprop(struct port_info *pi, const char *name, uint_t size, void *val)
969 {
970 struct link_config *lc = &pi->link_cfg;
971 int v;
972
973 if (strcmp(name, T4PROP_TMR_IDX) == 0)
974 v = pi->tmr_idx;
975 else if (strcmp(name, T4PROP_PKTC_IDX) == 0)
976 v = pi->pktc_idx;
977 else if (strcmp(name, T4PROP_HW_CSUM) == 0)
978 v = (pi->features & CXGBE_HW_CSUM) ? 1 : 0;
979 else if (strcmp(name, T4PROP_HW_LSO) == 0)
980 v = (pi->features & CXGBE_HW_LSO) ? 1 : 0;
981 else if (strcmp(name, T4PROP_TX_PAUSE) == 0)
982 v = (lc->fc & PAUSE_TX) ? 1 : 0;
983 else if (strcmp(name, T4PROP_RX_PAUSE) == 0)
984 v = (lc->fc & PAUSE_RX) ? 1 : 0;
985 #if MAC_VERSION == 1
986 else if (strcmp(name, T4PROP_MTU) == 0)
987 v = pi->mtu;
988 #endif
989 else
990 return (ENOTSUP);
991
992 (void) snprintf(val, size, "%d", v);
993 return (0);
994 }
995
996 static int
setprop(struct port_info * pi,const char * name,const void * val)997 setprop(struct port_info *pi, const char *name, const void *val)
998 {
999 struct adapter *sc = pi->adapter;
1000 long v;
1001 int i, rc = 0, relink = 0, rx_mode = 0;
1002 struct sge_rxq *rxq;
1003 struct link_config lc_old, *lc = &pi->link_cfg;
1004
1005 /*
1006 * Save a copy of link_config. This can be used to restore link_config
1007 * if t4_link_start() fails.
1008 */
1009 bcopy(lc, &lc_old, sizeof (struct link_config));
1010
1011 (void) ddi_strtol(val, NULL, 0, &v);
1012
1013 if (strcmp(name, T4PROP_TMR_IDX) == 0) {
1014 if (v < 0 || v >= SGE_NTIMERS)
1015 return (EINVAL);
1016 if (v == pi->tmr_idx)
1017 return (0);
1018
1019 /* LINTED: E_ASSIGN_NARROW_CONV */
1020 pi->tmr_idx = v;
1021 for_each_rxq(pi, i, rxq) {
1022 rxq->iq.intr_params = V_QINTR_TIMER_IDX(v) |
1023 V_QINTR_CNT_EN(pi->pktc_idx >= 0);
1024 }
1025
1026 } else if (strcmp(name, T4PROP_PKTC_IDX) == 0) {
1027 if (v >= SGE_NCOUNTERS)
1028 return (EINVAL);
1029 if (v == pi->pktc_idx || (v < 0 && pi->pktc_idx == -1))
1030 return (0);
1031
1032 /* LINTED: E_ASSIGN_NARROW_CONV */
1033 pi->pktc_idx = v < 0 ? -1 : v;
1034 for_each_rxq(pi, i, rxq) {
1035 rxq->iq.intr_params = V_QINTR_TIMER_IDX(pi->tmr_idx) |
1036 /* takes effect right away */
1037 V_QINTR_CNT_EN(v >= 0);
1038 /* LINTED: E_ASSIGN_NARROW_CONV */
1039 rxq->iq.intr_pktc_idx = v; /* this needs fresh plumb */
1040 }
1041 } else if (strcmp(name, T4PROP_HW_CSUM) == 0) {
1042 if (v != 0 && v != 1)
1043 return (EINVAL);
1044 if (v == 1)
1045 pi->features |= CXGBE_HW_CSUM;
1046 else
1047 pi->features &= ~CXGBE_HW_CSUM;
1048 } else if (strcmp(name, T4PROP_HW_LSO) == 0) {
1049 if (v != 0 && v != 1)
1050 return (EINVAL);
1051 if (v == 1)
1052 pi->features |= CXGBE_HW_LSO;
1053 else
1054 pi->features &= ~CXGBE_HW_LSO;
1055 } else if (strcmp(name, T4PROP_TX_PAUSE) == 0) {
1056 if (v != 0 && v != 1)
1057 return (EINVAL);
1058
1059 if (v != 0)
1060 lc->requested_fc |= PAUSE_TX;
1061 else
1062 lc->requested_fc &= ~PAUSE_TX;
1063
1064 relink = 1;
1065
1066 } else if (strcmp(name, T4PROP_RX_PAUSE) == 0) {
1067 if (v != 0 && v != 1)
1068 return (EINVAL);
1069
1070 if (v != 0)
1071 lc->requested_fc |= PAUSE_RX;
1072 else
1073 lc->requested_fc &= ~PAUSE_RX;
1074
1075 relink = 1;
1076 }
1077 #if MAC_VERSION == 1
1078 else if (strcmp(name, T4PROP_MTU) == 0) {
1079 if (v < 46 || v > MAX_MTU)
1080 return (EINVAL);
1081 if (v == pi->mtu)
1082 return (0);
1083
1084 pi->mtu = (int)v;
1085 (void) mac_maxsdu_update(pi->mh, v);
1086 rx_mode = 1;
1087 }
1088 #endif
1089 else
1090 return (ENOTSUP);
1091
1092 if (!(relink || rx_mode))
1093 return (0);
1094
1095 /* If we are here, either relink or rx_mode is 1 */
1096 if (isset(&sc->open_device_map, pi->port_id) != 0) {
1097 if (relink != 0) {
1098 rc = begin_synchronized_op(pi, 1, 1);
1099 if (rc != 0)
1100 return (rc);
1101 rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, lc);
1102 end_synchronized_op(pi, 1);
1103 if (rc != 0) {
1104 cxgb_printf(pi->dip, CE_WARN,
1105 "start_link failed:%d", rc);
1106 /* Restore link_config */
1107 bcopy(&lc_old, lc, sizeof (struct link_config));
1108 }
1109 } else if (rx_mode != 0) {
1110 rc = begin_synchronized_op(pi, 1, 1);
1111 if (rc != 0)
1112 return (rc);
1113 rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, v, -1, -1,
1114 -1, -1, false);
1115 end_synchronized_op(pi, 1);
1116 if (rc != 0) {
1117 cxgb_printf(pi->dip, CE_WARN,
1118 "set_rxmode failed: %d", rc);
1119 }
1120 }
1121 return (rc);
1122 }
1123
1124 return (0);
1125 }
1126
1127 void
t4_mc_init(struct port_info * pi)1128 t4_mc_init(struct port_info *pi)
1129 {
1130 pi->mc = &t4_m_callbacks;
1131 pi->props = t4_priv_props;
1132 }
1133
1134 void
t4_os_link_changed(struct adapter * sc,int idx,int link_stat)1135 t4_os_link_changed(struct adapter *sc, int idx, int link_stat)
1136 {
1137 struct port_info *pi = sc->port[idx];
1138
1139 mac_link_update(pi->mh, link_stat ? LINK_STATE_UP : LINK_STATE_DOWN);
1140 }
1141
1142 /* ARGSUSED */
1143 void
t4_mac_rx(struct port_info * pi,struct sge_rxq * rxq,mblk_t * m)1144 t4_mac_rx(struct port_info *pi, struct sge_rxq *rxq, mblk_t *m)
1145 {
1146 mac_rx(pi->mh, NULL, m);
1147 }
1148