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 * Copyright 2024 Oxide Computer Company
14 */
15
16 /*
17 * Intel I225/226 Ethernet Driver. This is the same MAC that is found in the
18 * e1000 and igb drivers, but Intel decided it would be a different driver and
19 * so here we are.
20 */
21
22 #include <sys/sysmacros.h>
23
24 #include "igc.h"
25
26 typedef struct {
27 enum igc_media_type imm_phy;
28 uint16_t imm_speed;
29 mac_ether_media_t imm_media;
30 } igc_media_map_t;
31
32 static const igc_media_map_t igc_media_map[] = {
33 { igc_media_type_copper, SPEED_10, ETHER_MEDIA_10BASE_T },
34 { igc_media_type_copper, SPEED_100, ETHER_MEDIA_100BASE_TX },
35 { igc_media_type_copper, SPEED_1000, ETHER_MEDIA_1000BASE_T },
36 { igc_media_type_copper, SPEED_2500, ETHER_MEDIA_2500BASE_T },
37 };
38
39 static mac_ether_media_t
igc_link_to_media(igc_t * igc)40 igc_link_to_media(igc_t *igc)
41 {
42 switch (igc->igc_link_state) {
43 case LINK_STATE_UP:
44 break;
45 case LINK_STATE_DOWN:
46 return (ETHER_MEDIA_NONE);
47 default:
48 return (ETHER_MEDIA_UNKNOWN);
49 }
50
51 for (size_t i = 0; i < ARRAY_SIZE(igc_media_map); i++) {
52 const igc_media_map_t *map = &igc_media_map[i];
53 if (igc->igc_hw.phy.media_type == map->imm_phy &&
54 igc->igc_link_speed == map->imm_speed) {
55 return (map->imm_media);
56 }
57 }
58
59 return (ETHER_MEDIA_UNKNOWN);
60 }
61
62 /*
63 * The following stats are skipped because there is no good way to get it from
64 * hardware or we don't know how to perform such a mapping:
65 *
66 * - MAC_STAT_UNKNOWNS
67 * - MAC_STAT_UNDERFLOWS
68 * - MAC_STAT_OVERFLOWS
69 * - ETHER_STAT_SQE_ERRORS
70 * - ETHER_STAT_MACRCV_ERRORS
71 */
72 static int
igc_m_getstat(void * drv,uint_t stat,uint64_t * valp)73 igc_m_getstat(void *drv, uint_t stat, uint64_t *valp)
74 {
75 igc_t *igc = drv;
76 igc_stats_t *stats = &igc->igc_stats;
77 int ret = 0;
78 uint32_t an_adv;
79
80 mutex_enter(&igc->igc_lock);
81 an_adv = igc->igc_hw.phy.autoneg_advertised;
82
83 switch (stat) {
84 /* MIB-II stats (RFC 1213 and RFC 1573) */
85 case MAC_STAT_IFSPEED:
86 *valp = (uint64_t)igc->igc_link_speed * 1000000;
87 break;
88 case MAC_STAT_MULTIRCV:
89 stats->is_mprc.value.ui64 += igc_read32(igc, IGC_MPRC);
90 *valp = stats->is_mprc.value.ui64;
91 break;
92 case MAC_STAT_BRDCSTRCV:
93 stats->is_bprc.value.ui64 += igc_read32(igc, IGC_BPRC);
94 *valp = stats->is_bprc.value.ui64;
95 break;
96 case MAC_STAT_MULTIXMT:
97 stats->is_mptc.value.ui64 += igc_read32(igc, IGC_MPTC);
98 *valp = stats->is_mptc.value.ui64;
99 break;
100 case MAC_STAT_BRDCSTXMT:
101 stats->is_bptc.value.ui64 += igc_read32(igc, IGC_BPTC);
102 *valp = stats->is_bptc.value.ui64;
103 break;
104 case MAC_STAT_NORCVBUF:
105 stats->is_rnbc.value.ui64 += igc_read32(igc, IGC_RNBC);
106 *valp = stats->is_rnbc.value.ui64;
107 break;
108 case MAC_STAT_IERRORS:
109 stats->is_crcerrs.value.ui64 += igc_read32(igc, IGC_CRCERRS);
110 stats->is_rlec.value.ui64 += igc_read32(igc, IGC_RLEC);
111 stats->is_algnerrc.value.ui64 += igc_read32(igc, IGC_ALGNERRC);
112
113 *valp = stats->is_crcerrs.value.ui64 +
114 stats->is_rlec.value.ui64 + stats->is_algnerrc.value.ui64;
115 break;
116 case MAC_STAT_OERRORS:
117 stats->is_ecol.value.ui64 += igc_read32(igc, IGC_ECOL);
118 stats->is_latecol.value.ui64 += igc_read32(igc, IGC_LATECOL);
119
120 *valp = stats->is_ecol.value.ui64 +
121 stats->is_latecol.value.ui64;
122 break;
123 case MAC_STAT_COLLISIONS:
124 stats->is_colc.value.ui64 += igc_read32(igc, IGC_COLC);
125 *valp = stats->is_colc.value.ui64;
126 break;
127 case MAC_STAT_RBYTES:
128 igc_stats_update_u64(igc, &stats->is_tor, IGC_TORL);
129 *valp = stats->is_tor.value.ui64;
130 break;
131 case MAC_STAT_IPACKETS:
132 stats->is_tpr.value.ui64 += igc_read32(igc, IGC_TPR);
133 *valp = stats->is_tpr.value.ui64;
134 break;
135 case MAC_STAT_OBYTES:
136 igc_stats_update_u64(igc, &stats->is_tor, IGC_TOTL);
137 *valp = stats->is_tot.value.ui64;
138 break;
139 case MAC_STAT_OPACKETS:
140 stats->is_tpt.value.ui64 += igc_read32(igc, IGC_TPT);
141 *valp = stats->is_tpt.value.ui64;
142 break;
143 case MAC_STAT_UNDERFLOWS:
144 stats->is_ruc.value.ui64 += igc_read32(igc, IGC_RUC);
145 *valp = stats->is_ruc.value.ui64;
146 break;
147 case MAC_STAT_OVERFLOWS:
148 stats->is_roc.value.ui64 += igc_read32(igc, IGC_ROC);
149 *valp = stats->is_roc.value.ui64;
150 break;
151 /* RFC 1643 stats */
152 case ETHER_STAT_ALIGN_ERRORS:
153 stats->is_algnerrc.value.ui64 += igc_read32(igc, IGC_ALGNERRC);
154 *valp = stats->is_algnerrc.value.ui64;
155 break;
156 case ETHER_STAT_FCS_ERRORS:
157 stats->is_crcerrs.value.ui64 += igc_read32(igc, IGC_CRCERRS);
158 *valp = stats->is_crcerrs.value.ui64;
159 break;
160 case ETHER_STAT_FIRST_COLLISIONS:
161 stats->is_scc.value.ui64 += igc_read32(igc, IGC_SCC);
162 *valp = stats->is_scc.value.ui64;
163 break;
164 case ETHER_STAT_MULTI_COLLISIONS:
165 stats->is_mcc.value.ui64 += igc_read32(igc, IGC_MCC);
166 *valp = stats->is_mcc.value.ui64;
167 break;
168 case ETHER_STAT_DEFER_XMTS:
169 stats->is_dc.value.ui64 += igc_read32(igc, IGC_DC);
170 *valp = stats->is_dc.value.ui64;
171 break;
172 case ETHER_STAT_TX_LATE_COLLISIONS:
173 stats->is_latecol.value.ui64 += igc_read32(igc, IGC_LATECOL);
174 *valp = stats->is_latecol.value.ui64;
175 break;
176 case ETHER_STAT_EX_COLLISIONS:
177 stats->is_ecol.value.ui64 += igc_read32(igc, IGC_ECOL);
178 *valp = stats->is_ecol.value.ui64;
179 break;
180 case ETHER_STAT_MACXMT_ERRORS:
181 stats->is_ecol.value.ui64 += igc_read32(igc, IGC_ECOL);
182 *valp = stats->is_ecol.value.ui64;
183 break;
184 case ETHER_STAT_CARRIER_ERRORS:
185 stats->is_htdpmc.value.ui64 += igc_read32(igc, IGC_HTDPMC);
186 *valp = stats->is_htdpmc.value.ui64;
187 break;
188 case ETHER_STAT_TOOLONG_ERRORS:
189 stats->is_roc.value.ui64 += igc_read32(igc, IGC_ROC);
190 *valp = stats->is_roc.value.ui64;
191 break;
192 /* MII/GMII stats */
193 case ETHER_STAT_XCVR_ADDR:
194 *valp = igc->igc_hw.phy.addr;
195 break;
196 case ETHER_STAT_XCVR_ID:
197 *valp = igc->igc_hw.phy.id | igc->igc_hw.phy.revision;
198 break;
199 case ETHER_STAT_XCVR_INUSE:
200 *valp = igc_link_to_media(igc);
201 break;
202 case ETHER_STAT_CAP_2500FDX:
203 case ETHER_STAT_CAP_1000FDX:
204 case ETHER_STAT_CAP_100FDX:
205 case ETHER_STAT_CAP_100HDX:
206 case ETHER_STAT_CAP_10FDX:
207 case ETHER_STAT_CAP_10HDX:
208 case ETHER_STAT_CAP_ASMPAUSE:
209 case ETHER_STAT_CAP_PAUSE:
210 case ETHER_STAT_CAP_AUTONEG:
211 /*
212 * These are all about what the device is capable of and every
213 * device is capable of this that we support right now.
214 */
215 *valp = 1;
216 break;
217 case ETHER_STAT_ADV_CAP_2500FDX:
218 *valp = (an_adv & ADVERTISE_2500_FULL) != 0;
219 break;
220 case ETHER_STAT_ADV_CAP_1000FDX:
221 *valp = (an_adv & ADVERTISE_1000_FULL) != 0;
222 break;
223 case ETHER_STAT_ADV_CAP_100FDX:
224 *valp = (an_adv & ADVERTISE_100_FULL) != 0;
225 break;
226 case ETHER_STAT_ADV_CAP_100HDX:
227 *valp = (an_adv & ADVERTISE_100_HALF) != 0;
228 break;
229 case ETHER_STAT_ADV_CAP_10FDX:
230 *valp = (an_adv & ADVERTISE_10_FULL) != 0;
231 break;
232 case ETHER_STAT_ADV_CAP_10HDX:
233 *valp = (an_adv & ADVERTISE_10_HALF) != 0;
234 break;
235 case ETHER_STAT_ADV_CAP_ASMPAUSE:
236 *valp = (igc->igc_phy_an_adv & NWAY_AR_ASM_DIR) != 0;
237 break;
238 case ETHER_STAT_ADV_CAP_PAUSE:
239 *valp = (igc->igc_phy_an_adv & NWAY_AR_PAUSE) != 0;
240 break;
241 case ETHER_STAT_ADV_CAP_AUTONEG:
242 *valp = igc->igc_hw.mac.autoneg;
243 break;
244 case ETHER_STAT_LP_CAP_2500FDX:
245 *valp = (igc->igc_phy_mmd_sts & MMD_AN_STS1_LP_2P5T_CAP) != 0;
246 break;
247 case ETHER_STAT_LP_CAP_1000FDX:
248 *valp = (igc->igc_phy_1000t_status & SR_1000T_LP_FD_CAPS) != 0;
249 break;
250 case ETHER_STAT_LP_CAP_100FDX:
251 *valp = (igc->igc_phy_lp & NWAY_LPAR_100TX_FD_CAPS) != 0;
252 break;
253 case ETHER_STAT_LP_CAP_100HDX:
254 *valp = (igc->igc_phy_lp & NWAY_LPAR_100TX_HD_CAPS) != 0;
255 break;
256 case ETHER_STAT_LP_CAP_10FDX:
257 *valp = (igc->igc_phy_lp & NWAY_LPAR_10T_FD_CAPS) != 0;
258 break;
259 case ETHER_STAT_LP_CAP_10HDX:
260 *valp = (igc->igc_phy_lp & NWAY_LPAR_10T_HD_CAPS) != 0;
261 break;
262 case ETHER_STAT_LP_CAP_ASMPAUSE:
263 *valp = (igc->igc_phy_lp & NWAY_AR_ASM_DIR) != 0;
264 break;
265 case ETHER_STAT_LP_CAP_PAUSE:
266 *valp = (igc->igc_phy_lp & NWAY_LPAR_PAUSE) != 0;
267 break;
268 case ETHER_STAT_LP_CAP_AUTONEG:
269 *valp = (igc->igc_phy_ext_status & NWAY_ER_LP_NWAY_CAPS) != 0;
270 break;
271 case ETHER_STAT_LINK_ASMPAUSE:
272 *valp = (igc->igc_hw.fc.current_mode == igc_fc_full ||
273 igc->igc_hw.fc.current_mode == igc_fc_rx_pause);
274 break;
275 case ETHER_STAT_LINK_PAUSE:
276 *valp = (igc->igc_hw.fc.current_mode == igc_fc_full ||
277 igc->igc_hw.fc.current_mode == igc_fc_tx_pause);
278 break;
279 case ETHER_STAT_LINK_AUTONEG:
280 *valp = igc->igc_hw.mac.autoneg;
281 break;
282 case ETHER_STAT_LINK_DUPLEX:
283 *valp = igc->igc_link_duplex;
284 break;
285 case ETHER_STAT_CAP_REMFAULT:
286 *valp = 1;
287 break;
288 case ETHER_STAT_ADV_REMFAULT:
289 *valp = (igc->igc_phy_an_adv & NWAY_AR_REMOTE_FAULT) != 0;
290 break;
291 case ETHER_STAT_LP_REMFAULT:
292 *valp = (igc->igc_phy_lp & NWAY_LPAR_REMOTE_FAULT) != 0;
293 break;
294
295 case ETHER_STAT_TOOSHORT_ERRORS:
296 stats->is_ruc.value.ui64 += igc_read32(igc, IGC_RUC);
297 *valp = stats->is_ruc.value.ui64;
298 break;
299
300 case ETHER_STAT_JABBER_ERRORS:
301 stats->is_rjc.value.ui64 += igc_read32(igc, IGC_RJC);
302 *valp = stats->is_rjc.value.ui64;
303 break;
304
305 /*
306 * Unsupported speeds.
307 */
308 case ETHER_STAT_CAP_100T4:
309 case ETHER_STAT_CAP_1000HDX:
310 case ETHER_STAT_CAP_10GFDX:
311 case ETHER_STAT_CAP_40GFDX:
312 case ETHER_STAT_CAP_100GFDX:
313 case ETHER_STAT_CAP_5000FDX:
314 case ETHER_STAT_CAP_25GFDX:
315 case ETHER_STAT_CAP_50GFDX:
316 case ETHER_STAT_CAP_200GFDX:
317 case ETHER_STAT_CAP_400GFDX:
318 case ETHER_STAT_ADV_CAP_100T4:
319 case ETHER_STAT_ADV_CAP_1000HDX:
320 case ETHER_STAT_ADV_CAP_10GFDX:
321 case ETHER_STAT_ADV_CAP_40GFDX:
322 case ETHER_STAT_ADV_CAP_100GFDX:
323 case ETHER_STAT_ADV_CAP_5000FDX:
324 case ETHER_STAT_ADV_CAP_25GFDX:
325 case ETHER_STAT_ADV_CAP_50GFDX:
326 case ETHER_STAT_ADV_CAP_200GFDX:
327 case ETHER_STAT_ADV_CAP_400GFDX:
328 *valp = 0;
329 break;
330
331 /*
332 * These are values that aren't supported by igc(4D); however, some of
333 * the MII registers can be used to answer this based on the
334 * MultiGBASE-T spec (and others).
335 */
336 case ETHER_STAT_LP_CAP_1000HDX:
337 *valp = (igc->igc_phy_1000t_status & SR_1000T_LP_HD_CAPS) != 0;
338 break;
339 case ETHER_STAT_LP_CAP_100T4:
340 *valp = (igc->igc_phy_lp & NWAY_LPAR_100T4_CAPS) != 0;
341 break;
342 case ETHER_STAT_LP_CAP_10GFDX:
343 *valp = (igc->igc_phy_mmd_sts & MMD_AN_STS1_LP_10T_CAP) != 0;
344 break;
345 case ETHER_STAT_LP_CAP_40GFDX:
346 *valp = (igc->igc_phy_mmd_sts & MMD_AN_STS1_LP_40T_CAP) != 0;
347 break;
348 case ETHER_STAT_LP_CAP_5000FDX:
349 *valp = (igc->igc_phy_mmd_sts & MMD_AN_STS1_LP_5T_CAP) != 0;
350 break;
351 case ETHER_STAT_LP_CAP_25GFDX:
352 *valp = (igc->igc_phy_mmd_sts & MMD_AN_STS1_LP_25T_CAP) != 0;
353 break;
354 case ETHER_STAT_LP_CAP_50GFDX:
355 case ETHER_STAT_LP_CAP_100GFDX:
356 case ETHER_STAT_LP_CAP_200GFDX:
357 case ETHER_STAT_LP_CAP_400GFDX:
358 *valp = 0;
359 break;
360 default:
361 ret = ENOTSUP;
362 }
363 mutex_exit(&igc->igc_lock);
364
365 return (ret);
366 }
367
368 static void
igc_m_stop(void * drv)369 igc_m_stop(void *drv)
370 {
371 igc_t *igc = drv;
372
373 igc_hw_intr_disable(igc);
374 (void) igc_reset_hw(&igc->igc_hw);
375 igc_rx_drain(igc);
376 igc_rx_data_free(igc);
377 igc_tx_data_free(igc);
378
379 /*
380 * Now that we're fully stopped, remove all of our state tracking.
381 */
382 mutex_enter(&igc->igc_lock);
383 igc->igc_attach &= ~IGC_ATTACH_TX_DATA;
384 igc->igc_attach &= ~IGC_ATTACH_RX_DATA;
385 igc->igc_attach &= ~IGC_ATTACH_MAC_START;
386 mutex_exit(&igc->igc_lock);
387 }
388
389 static int
igc_m_start(void * drv)390 igc_m_start(void *drv)
391 {
392 int ret;
393 igc_t *igc = drv;
394
395 mutex_enter(&igc->igc_lock);
396 igc->igc_attach |= IGC_ATTACH_MAC_START;
397 mutex_exit(&igc->igc_lock);
398
399 /*
400 * Ensure that the phy is powerd on.
401 */
402 igc_power_up_phy(&igc->igc_hw);
403
404 if (!igc_rx_data_alloc(igc)) {
405 ret = ENOMEM;
406 goto cleanup;
407 }
408 mutex_enter(&igc->igc_lock);
409 igc->igc_attach |= IGC_ATTACH_RX_DATA;
410 mutex_exit(&igc->igc_lock);
411
412 if (!igc_tx_data_alloc(igc)) {
413 ret = ENOMEM;
414 goto cleanup;
415 }
416 mutex_enter(&igc->igc_lock);
417 igc->igc_attach |= IGC_ATTACH_TX_DATA;
418 mutex_exit(&igc->igc_lock);
419
420 if (!igc_hw_common_init(igc)) {
421 ret = EIO;
422 goto cleanup;
423 }
424
425 /*
426 * The above hardware reset ensures that the latest requested link
427 * properties are set and that the packet sizes and related are
428 * programmed. Now we must go through and program the ring information
429 * into the hardware and enable interrupts. Once that's done we're good
430 * to go.
431 */
432 igc_rx_hw_init(igc);
433 igc_tx_hw_init(igc);
434 igc_hw_intr_enable(igc);
435
436 return (0);
437
438 cleanup:
439 mutex_enter(&igc->igc_lock);
440 if ((igc->igc_attach & IGC_ATTACH_TX_DATA) != 0) {
441 igc_tx_data_free(igc);
442 igc->igc_attach &= ~IGC_ATTACH_TX_DATA;
443 }
444
445 if ((igc->igc_attach & IGC_ATTACH_RX_DATA) != 0) {
446 igc_rx_data_free(igc);
447 igc->igc_attach &= ~IGC_ATTACH_RX_DATA;
448 }
449
450 igc->igc_attach &= ~IGC_ATTACH_MAC_START;
451 mutex_exit(&igc->igc_lock);
452
453 return (ret);
454 }
455
456 static int
igc_m_setpromisc(void * drv,boolean_t en)457 igc_m_setpromisc(void *drv, boolean_t en)
458 {
459 igc_t *igc = drv;
460 uint32_t reg;
461
462 mutex_enter(&igc->igc_lock);
463
464 reg = igc_read32(igc, IGC_RCTL);
465 if (en) {
466 reg |= IGC_RCTL_UPE | IGC_RCTL_MPE;
467 igc->igc_promisc = true;
468 } else {
469 reg &= ~(IGC_RCTL_UPE | IGC_RCTL_MPE);
470 igc->igc_promisc = false;
471 }
472 igc_write32(igc, IGC_RCTL, reg);
473 mutex_exit(&igc->igc_lock);
474
475 return (0);
476 }
477
478 static int
igc_m_multicast(void * drv,boolean_t add,const uint8_t * mac)479 igc_m_multicast(void *drv, boolean_t add, const uint8_t *mac)
480 {
481 int ret = 0;
482 igc_t *igc = drv;
483
484 if ((mac[0] & 0x01) == 0) {
485 return (EINVAL);
486 }
487
488 mutex_enter(&igc->igc_lock);
489 if (add) {
490 bool space = false;
491
492 for (uint16_t i = 0; i < igc->igc_nmcast; i++) {
493 if (igc->igc_mcast[i].ia_valid)
494 continue;
495
496 bcopy(mac, igc->igc_mcast[i].ia_mac, ETHERADDRL);
497 igc->igc_mcast[i].ia_valid = true;
498 space = true;
499 break;
500 }
501
502 if (!space) {
503 ret = ENOSPC;
504 }
505 } else {
506 bool found = false;
507
508 for (uint16_t i = 0; i < igc->igc_nmcast; i++) {
509 if (!igc->igc_mcast[i].ia_valid || bcmp(mac,
510 igc->igc_mcast[i].ia_mac, ETHERADDRL) != 0) {
511 continue;
512 }
513
514 bzero(igc->igc_mcast[i].ia_mac, ETHERADDRL);
515 igc->igc_mcast[i].ia_valid = false;
516 found = true;
517 break;
518 }
519
520 if (!found) {
521 ret = ENOENT;
522 }
523 }
524 igc_multicast_sync(igc);
525 mutex_exit(&igc->igc_lock);
526
527 return (ret);
528 }
529
530 static int
igc_group_add_mac(void * gr_drv,const uint8_t * mac)531 igc_group_add_mac(void *gr_drv, const uint8_t *mac)
532 {
533 igc_t *igc = gr_drv;
534
535 ASSERT3U(mac[0] & 0x01, ==, 0);
536
537 mutex_enter(&igc->igc_lock);
538 for (uint16_t i = 0; i < igc->igc_nucast; i++) {
539 int ret;
540
541 if (igc->igc_ucast[i].ia_valid)
542 continue;
543
544 bcopy(mac, igc->igc_ucast[i].ia_mac, ETHERADDRL);
545 igc->igc_ucast[i].ia_valid = true;
546 ret = igc_rar_set(&igc->igc_hw, igc->igc_ucast[i].ia_mac, i);
547 VERIFY3S(ret, ==, IGC_SUCCESS);
548 mutex_exit(&igc->igc_lock);
549 return (0);
550 }
551 mutex_exit(&igc->igc_lock);
552
553 return (ENOSPC);
554 }
555
556 static int
igc_group_rem_mac(void * gr_drv,const uint8_t * mac)557 igc_group_rem_mac(void *gr_drv, const uint8_t *mac)
558 {
559 igc_t *igc = gr_drv;
560
561 ASSERT3U(mac[0] & 0x01, ==, 0);
562
563 mutex_enter(&igc->igc_lock);
564 for (uint16_t i = 0; i < igc->igc_nucast; i++) {
565 int ret;
566
567 if (!igc->igc_ucast[i].ia_valid || bcmp(mac,
568 igc->igc_ucast[i].ia_mac, ETHERADDRL) != 0) {
569 continue;
570 }
571
572 bzero(igc->igc_ucast[i].ia_mac, ETHERADDRL);
573 igc->igc_ucast[i].ia_valid = false;
574 ret = igc_rar_set(&igc->igc_hw, igc->igc_ucast[i].ia_mac, i);
575 VERIFY3S(ret, ==, IGC_SUCCESS);
576 mutex_exit(&igc->igc_lock);
577 return (0);
578 }
579 mutex_exit(&igc->igc_lock);
580
581 return (ENOENT);
582 }
583
584 int
igc_tx_ring_stat(mac_ring_driver_t rh,uint_t stat,uint64_t * val)585 igc_tx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
586 {
587 igc_tx_ring_t *tx_ring = (igc_tx_ring_t *)rh;
588
589 switch (stat) {
590 case MAC_STAT_OBYTES:
591 *val = tx_ring->itr_stat.its_obytes.value.ui64;
592 break;
593 case MAC_STAT_OPACKETS:
594 *val = tx_ring->itr_stat.its_opackets.value.ui64;
595 break;
596 default:
597 *val = 0;
598 return (ENOTSUP);
599 }
600
601 return (0);
602 }
603
604 int
igc_rx_ring_start(mac_ring_driver_t rh,uint64_t gen)605 igc_rx_ring_start(mac_ring_driver_t rh, uint64_t gen)
606 {
607 igc_rx_ring_t *rx_ring = (igc_rx_ring_t *)rh;
608
609 mutex_enter(&rx_ring->irr_lock);
610 rx_ring->irr_gen = gen;
611 mutex_exit(&rx_ring->irr_lock);
612
613 return (0);
614 }
615
616 mblk_t *
igc_rx_ring_poll(void * drv,int nbytes)617 igc_rx_ring_poll(void *drv, int nbytes)
618 {
619 mblk_t *mp;
620 igc_rx_ring_t *ring = drv;
621
622 ASSERT3S(nbytes, >, 0);
623 if (nbytes == 0) {
624 return (NULL);
625 }
626
627 mutex_enter(&ring->irr_lock);
628 mp = igc_ring_rx(ring, nbytes);
629 mutex_exit(&ring->irr_lock);
630
631 return (mp);
632 }
633
634 int
igc_rx_ring_stat(mac_ring_driver_t rh,uint_t stat,uint64_t * val)635 igc_rx_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val)
636 {
637 igc_rx_ring_t *rx_ring = (igc_rx_ring_t *)rh;
638
639 switch (stat) {
640 case MAC_STAT_RBYTES:
641 *val = rx_ring->irr_stat.irs_rbytes.value.ui64;
642 break;
643 case MAC_STAT_IPACKETS:
644 *val = rx_ring->irr_stat.irs_ipackets.value.ui64;
645 break;
646 default:
647 *val = 0;
648 return (ENOTSUP);
649 }
650
651 return (0);
652 }
653
654 int
igc_rx_ring_intr_enable(mac_intr_handle_t ih)655 igc_rx_ring_intr_enable(mac_intr_handle_t ih)
656 {
657 igc_rx_ring_t *ring = (igc_rx_ring_t *)ih;
658 igc_t *igc = ring->irr_igc;
659
660 /*
661 * Disabling a ring requires us updating shared device registers. So we
662 * use the igc_lock to protect that. We also grab the irr_lock, so we
663 * can synchronize with the I/O path.
664 */
665 mutex_enter(&igc->igc_lock);
666 mutex_enter(&ring->irr_lock);
667 ring->irr_flags &= ~IGC_RXR_F_POLL;
668 mutex_exit(&ring->irr_lock);
669
670 /*
671 * Re-enable interrupts. We update our EIMS value and then update both
672 * the EIMS and EIAC. We update the whole set with the EIMS just to
673 * simplify things.
674 */
675 igc->igc_eims |= 1 << ring->irr_intr_idx;
676 igc_write32(igc, IGC_EIMS, igc->igc_eims);
677 igc_write32(igc, IGC_EIAC, igc->igc_eims);
678 mutex_exit(&igc->igc_lock);
679 return (0);
680 }
681
682 int
igc_rx_ring_intr_disable(mac_intr_handle_t ih)683 igc_rx_ring_intr_disable(mac_intr_handle_t ih)
684 {
685 igc_rx_ring_t *ring = (igc_rx_ring_t *)ih;
686 igc_t *igc = ring->irr_igc;
687
688 /*
689 * Disabling a ring requires us updating shared device registers. So we
690 * use the igc_lock to protect that. We also grab the irr_lock, so we
691 * can synchronize with the I/O path.
692 */
693 mutex_enter(&igc->igc_lock);
694 mutex_enter(&ring->irr_lock);
695 ring->irr_flags |= IGC_RXR_F_POLL;
696 mutex_exit(&ring->irr_lock);
697
698 /*
699 * Writing to the EIMC register masks off interrupts for this. We also
700 * clear this from EIAC as a means of making sure it also won't
701 * retrigger. We remove this queue from our global tracking set of what
702 * the eims value should be to simplify tracking.
703 */
704 igc_write32(igc, IGC_EIMC, 1 << ring->irr_intr_idx);
705 igc->igc_eims &= ~ (1 << ring->irr_intr_idx);
706 igc_write32(igc, IGC_EIAC, igc->igc_eims);
707 mutex_exit(&igc->igc_lock);
708
709 return (0);
710 }
711
712 static void
igc_fill_tx_ring(void * arg,mac_ring_type_t rtype,const int group_idx,const int ring_idx,mac_ring_info_t * infop,mac_ring_handle_t rh)713 igc_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_idx,
714 const int ring_idx, mac_ring_info_t *infop, mac_ring_handle_t rh)
715 {
716 igc_t *igc = arg;
717 igc_tx_ring_t *ring;
718
719 ASSERT3S(group_idx, ==, -1);
720 ASSERT3S(ring_idx, <, igc->igc_ntx_rings);
721
722 ring = &igc->igc_tx_rings[ring_idx];
723 ring->itr_rh = rh;
724
725 infop->mri_driver = (mac_ring_driver_t)ring;
726 infop->mri_start = NULL;
727 infop->mri_stop = NULL;
728 infop->mri_tx = igc_ring_tx;
729 infop->mri_stat = igc_tx_ring_stat;
730
731 if (igc->igc_intr_type == DDI_INTR_TYPE_MSIX) {
732 infop->mri_intr.mi_ddi_handle =
733 igc->igc_intr_handles[ring->itr_intr_idx];
734 }
735 }
736
737 static void
igc_fill_rx_ring(void * arg,mac_ring_type_t rtype,const int group_idx,const int ring_idx,mac_ring_info_t * infop,mac_ring_handle_t rh)738 igc_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_idx,
739 const int ring_idx, mac_ring_info_t *infop, mac_ring_handle_t rh)
740 {
741 igc_t *igc = arg;
742 igc_rx_ring_t *ring;
743
744 ASSERT3S(group_idx, ==, 0);
745 ASSERT3S(ring_idx, <, igc->igc_nrx_rings);
746
747 ring = &igc->igc_rx_rings[ring_idx];
748 ring->irr_rh = rh;
749
750 infop->mri_driver = (mac_ring_driver_t)ring;
751 infop->mri_start = igc_rx_ring_start;
752 infop->mri_stop = NULL;
753 infop->mri_poll = igc_rx_ring_poll;
754 infop->mri_stat = igc_rx_ring_stat;
755 infop->mri_intr.mi_handle = (mac_intr_handle_t)ring;
756 infop->mri_intr.mi_enable = igc_rx_ring_intr_enable;
757 infop->mri_intr.mi_disable = igc_rx_ring_intr_disable;
758
759 if (igc->igc_intr_type == DDI_INTR_TYPE_MSIX) {
760 infop->mri_intr.mi_ddi_handle =
761 igc->igc_intr_handles[ring->irr_intr_idx];
762 }
763 }
764
765 static void
igc_fill_rx_group(void * arg,mac_ring_type_t rtype,const int idx,mac_group_info_t * infop,mac_group_handle_t gh)766 igc_fill_rx_group(void *arg, mac_ring_type_t rtype, const int idx,
767 mac_group_info_t *infop, mac_group_handle_t gh)
768 {
769 igc_t *igc = arg;
770
771 if (rtype != MAC_RING_TYPE_RX) {
772 return;
773 }
774
775 igc->igc_rxg_hdl = gh;
776 infop->mgi_driver = (mac_group_driver_t)igc;
777 infop->mgi_start = NULL;
778 infop->mgi_stop = NULL;
779 infop->mgi_addmac = igc_group_add_mac;
780 infop->mgi_remmac = igc_group_rem_mac;
781 infop->mgi_count = igc->igc_nrx_rings;
782 }
783
784 static int
igc_led_set(void * drv,mac_led_mode_t mode,uint_t flags)785 igc_led_set(void *drv, mac_led_mode_t mode, uint_t flags)
786 {
787 igc_t *igc = drv;
788 uint32_t led;
789
790 if (flags != 0) {
791 return (EINVAL);
792 }
793
794 switch (mode) {
795 case MAC_LED_DEFAULT:
796 led = igc->igc_ledctl;
797 break;
798 case MAC_LED_IDENT:
799 led = igc->igc_ledctl_blink;
800 break;
801 case MAC_LED_OFF:
802 led = igc->igc_ledctl_off;
803 break;
804 case MAC_LED_ON:
805 led = igc->igc_ledctl_on;
806 break;
807 default:
808 return (ENOTSUP);
809 }
810
811 mutex_enter(&igc->igc_lock);
812 igc_write32(igc, IGC_LEDCTL, led);
813 igc->igc_led_mode = mode;
814 mutex_exit(&igc->igc_lock);
815
816 return (0);
817 }
818
819 static boolean_t
igc_m_getcapab(void * drv,mac_capab_t capab,void * data)820 igc_m_getcapab(void *drv, mac_capab_t capab, void *data)
821 {
822 igc_t *igc = drv;
823 mac_capab_rings_t *rings;
824 mac_capab_led_t *led;
825 uint32_t *cksump;
826
827 switch (capab) {
828 case MAC_CAPAB_RINGS:
829 rings = data;
830 rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
831 switch (rings->mr_type) {
832 case MAC_RING_TYPE_TX:
833 rings->mr_gnum = 0;
834 rings->mr_rnum = igc->igc_ntx_rings;
835 rings->mr_rget = igc_fill_tx_ring;
836 rings->mr_gget = NULL;
837 rings->mr_gaddring = NULL;
838 rings->mr_gremring = NULL;
839 break;
840 case MAC_RING_TYPE_RX:
841 rings->mr_gnum = 1;
842 rings->mr_rnum = igc->igc_nrx_rings;
843 rings->mr_rget = igc_fill_rx_ring;
844 rings->mr_gget = igc_fill_rx_group;
845 rings->mr_gaddring = NULL;
846 rings->mr_gremring = NULL;
847 break;
848 default:
849 return (B_FALSE);
850 }
851 break;
852 case MAC_CAPAB_HCKSUM:
853 cksump = data;
854
855 /*
856 * The hardware supports computing the full checksum on receive,
857 * but on transmit needs the partial checksum pre-computed.
858 */
859 *cksump = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
860 break;
861 case MAC_CAPAB_LED:
862 led = data;
863 led->mcl_flags = 0;
864 led->mcl_modes = MAC_LED_DEFAULT | MAC_LED_OFF | MAC_LED_ON |
865 MAC_LED_IDENT;
866 led->mcl_set = igc_led_set;
867 return (B_TRUE);
868 default:
869 return (B_FALSE);
870 }
871 return (B_TRUE);
872 }
873
874 void
igc_m_propinfo(void * drv,const char * name,mac_prop_id_t prop,mac_prop_info_handle_t prh)875 igc_m_propinfo(void *drv, const char *name, mac_prop_id_t prop,
876 mac_prop_info_handle_t prh)
877 {
878 igc_t *igc = drv;
879
880 switch (prop) {
881 case MAC_PROP_DUPLEX:
882 case MAC_PROP_SPEED:
883 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
884 break;
885 case MAC_PROP_AUTONEG:
886 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
887 mac_prop_info_set_default_uint8(prh, 1);
888 break;
889 case MAC_PROP_MTU:
890 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
891 mac_prop_info_set_range_uint32(prh, ETHERMIN,
892 igc->igc_limits.il_max_mtu);
893 mac_prop_info_set_default_uint32(prh, ETHERMTU);
894 break;
895 case MAC_PROP_FLOWCTRL:
896 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
897 mac_prop_info_set_default_link_flowctrl(prh, LINK_FLOWCTRL_BI);
898 break;
899 /*
900 * Right now, all igc devices support the same set of speeds and we
901 * attempt to advertise them all.
902 */
903 case MAC_PROP_ADV_10HDX_CAP:
904 case MAC_PROP_ADV_10FDX_CAP:
905 case MAC_PROP_ADV_100HDX_CAP:
906 case MAC_PROP_ADV_100FDX_CAP:
907 case MAC_PROP_ADV_1000FDX_CAP:
908 case MAC_PROP_ADV_2500FDX_CAP:
909 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
910 mac_prop_info_set_default_uint8(prh, 1);
911 break;
912 case MAC_PROP_EN_10HDX_CAP:
913 case MAC_PROP_EN_10FDX_CAP:
914 case MAC_PROP_EN_100HDX_CAP:
915 case MAC_PROP_EN_100FDX_CAP:
916 case MAC_PROP_EN_1000FDX_CAP:
917 case MAC_PROP_EN_2500FDX_CAP:
918 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
919 mac_prop_info_set_default_uint8(prh, 1);
920 break;
921 default:
922 break;
923 }
924 }
925
926 int
igc_m_getprop(void * drv,const char * name,mac_prop_id_t prop,uint_t pr_valsize,void * pr_val)927 igc_m_getprop(void *drv, const char *name, mac_prop_id_t prop,
928 uint_t pr_valsize, void *pr_val)
929 {
930 igc_t *igc = drv;
931 int ret = 0;
932 uint8_t *u8p;
933 uint64_t u64;
934 link_flowctrl_t flow;
935 mac_ether_media_t media;
936
937 mutex_enter(&igc->igc_lock);
938
939 switch (prop) {
940 case MAC_PROP_DUPLEX:
941 if (pr_valsize < sizeof (link_duplex_t)) {
942 ret = EOVERFLOW;
943 break;
944 }
945 bcopy(&igc->igc_link_duplex, pr_val, sizeof (link_duplex_t));
946 break;
947 case MAC_PROP_SPEED:
948 if (pr_valsize < sizeof (uint64_t)) {
949 ret = EOVERFLOW;
950 break;
951 }
952 u64 = (uint64_t)igc->igc_link_speed * 1000000;
953 bcopy(&u64, pr_val, sizeof (uint64_t));
954 break;
955 case MAC_PROP_STATUS:
956 if (pr_valsize < sizeof (link_state_t)) {
957 ret = EOVERFLOW;
958 break;
959 }
960 bcopy(&igc->igc_link_state, pr_val, sizeof (link_state_t));
961 break;
962 case MAC_PROP_MEDIA:
963 if (pr_valsize < sizeof (mac_ether_media_t)) {
964 ret = EOVERFLOW;
965 break;
966 }
967 media = igc_link_to_media(igc);
968 bcopy(&media, pr_val, sizeof (mac_ether_media_t));
969 break;
970 case MAC_PROP_AUTONEG:
971 if (pr_valsize < sizeof (uint8_t)) {
972 ret = EOVERFLOW;
973 break;
974 }
975 u8p = pr_val;
976 *u8p = igc->igc_hw.mac.autoneg;
977 break;
978 case MAC_PROP_MTU:
979 if (pr_valsize < sizeof (uint32_t)) {
980 ret = EOVERFLOW;
981 break;
982 }
983 bcopy(&igc->igc_mtu, pr_val, sizeof (uint32_t));
984 break;
985 case MAC_PROP_FLOWCTRL:
986 switch (igc->igc_hw.fc.requested_mode) {
987 case igc_fc_none:
988 flow = LINK_FLOWCTRL_NONE;
989 break;
990 case igc_fc_rx_pause:
991 flow = LINK_FLOWCTRL_RX;
992 break;
993 case igc_fc_tx_pause:
994 flow = LINK_FLOWCTRL_TX;
995 break;
996 case igc_fc_full:
997 flow = LINK_FLOWCTRL_BI;
998 break;
999 /*
1000 * We don't expect to get this value here; however, for
1001 * completeness of the switch's valid options we include it and
1002 * set it to the common firmware default of enabling
1003 * bi-direcitonal pause frames.
1004 */
1005 case igc_fc_default:
1006 flow = LINK_FLOWCTRL_BI;
1007 break;
1008 }
1009 bcopy(&flow, pr_val, sizeof (link_flowctrl_t));
1010 break;
1011 case MAC_PROP_ADV_10HDX_CAP:
1012 case MAC_PROP_ADV_10FDX_CAP:
1013 case MAC_PROP_ADV_100HDX_CAP:
1014 case MAC_PROP_ADV_100FDX_CAP:
1015 case MAC_PROP_ADV_1000FDX_CAP:
1016 case MAC_PROP_ADV_2500FDX_CAP:
1017 ret = ENOTSUP;
1018 break;
1019 case MAC_PROP_EN_10HDX_CAP:
1020 if (pr_valsize < sizeof (uint8_t)) {
1021 ret = EOVERFLOW;
1022 break;
1023 }
1024 u8p = pr_val;
1025 *u8p = (igc->igc_hw.phy.autoneg_advertised &
1026 ADVERTISE_10_HALF) != 0;
1027 break;
1028 case MAC_PROP_EN_10FDX_CAP:
1029 if (pr_valsize < sizeof (uint8_t)) {
1030 ret = EOVERFLOW;
1031 break;
1032 }
1033 u8p = pr_val;
1034 *u8p = (igc->igc_hw.phy.autoneg_advertised &
1035 ADVERTISE_10_FULL) != 0;
1036 break;
1037 case MAC_PROP_EN_100HDX_CAP:
1038 if (pr_valsize < sizeof (uint8_t)) {
1039 ret = EOVERFLOW;
1040 break;
1041 }
1042 u8p = pr_val;
1043 *u8p = (igc->igc_hw.phy.autoneg_advertised &
1044 ADVERTISE_100_HALF) != 0;
1045 break;
1046 case MAC_PROP_EN_100FDX_CAP:
1047 if (pr_valsize < sizeof (uint8_t)) {
1048 ret = EOVERFLOW;
1049 break;
1050 }
1051 u8p = pr_val;
1052 *u8p = (igc->igc_hw.phy.autoneg_advertised &
1053 ADVERTISE_100_FULL) != 0;
1054 break;
1055 case MAC_PROP_EN_1000FDX_CAP:
1056 if (pr_valsize < sizeof (uint8_t)) {
1057 ret = EOVERFLOW;
1058 break;
1059 }
1060 u8p = pr_val;
1061 *u8p = (igc->igc_hw.phy.autoneg_advertised &
1062 ADVERTISE_1000_FULL) != 0;
1063 break;
1064 case MAC_PROP_EN_2500FDX_CAP:
1065 if (pr_valsize < sizeof (uint8_t)) {
1066 ret = EOVERFLOW;
1067 break;
1068 }
1069 u8p = pr_val;
1070 *u8p = (igc->igc_hw.phy.autoneg_advertised &
1071 ADVERTISE_2500_FULL) != 0;
1072 break;
1073 default:
1074 ret = ENOTSUP;
1075 break;
1076 }
1077
1078 mutex_exit(&igc->igc_lock);
1079 return (ret);
1080 }
1081
1082 int
igc_m_setprop(void * drv,const char * name,mac_prop_id_t prop,uint_t size,const void * val)1083 igc_m_setprop(void *drv, const char *name, mac_prop_id_t prop, uint_t size,
1084 const void *val)
1085 {
1086 int ret = 0;
1087 bool update_link = true;
1088 igc_t *igc = drv;
1089 uint32_t fc, mtu;
1090 uint8_t en;
1091
1092 mutex_enter(&igc->igc_lock);
1093 switch (prop) {
1094 /*
1095 * The following properties are always read-only. Note, auto-negotiation
1096 * is here because we don't support turning it off right now. We leave
1097 * out unsupported speeds.
1098 */
1099 case MAC_PROP_DUPLEX:
1100 case MAC_PROP_SPEED:
1101 case MAC_PROP_STATUS:
1102 case MAC_PROP_AUTONEG:
1103 case MAC_PROP_ADV_2500FDX_CAP:
1104 case MAC_PROP_ADV_1000FDX_CAP:
1105 case MAC_PROP_ADV_1000HDX_CAP:
1106 case MAC_PROP_ADV_100FDX_CAP:
1107 case MAC_PROP_ADV_100HDX_CAP:
1108 case MAC_PROP_ADV_10HDX_CAP:
1109 case MAC_PROP_ADV_10FDX_CAP:
1110 case MAC_PROP_MEDIA:
1111 ret = ENOTSUP;
1112 break;
1113 /*
1114 * This is a property that we should support, but don't today.
1115 */
1116 case MAC_PROP_MTU:
1117 /*
1118 * Unfortunately, like our siblings igb and e1000g, we do not
1119 * currently support changing the MTU dynamically.
1120 */
1121 if ((igc->igc_attach & IGC_ATTACH_MAC_START) != 0) {
1122 ret = EBUSY;
1123 break;
1124 }
1125
1126 /*
1127 * Changing the MTU does not require us to update the link right
1128 * now as this can only be done while the device is stopped.
1129 */
1130 update_link = false;
1131
1132 bcopy(val, &mtu, sizeof (mtu));
1133 if (mtu < ETHERMIN || mtu > igc->igc_limits.il_max_mtu) {
1134 ret = EINVAL;
1135 break;
1136 }
1137
1138 /*
1139 * Verify that MAC will let us perform this operation. Once we
1140 * have confirmed that we will need to update our various buffer
1141 * sizes. Right now the driver requires that we increase the rx
1142 * buffer size to match the MTU. The tx buffer size is capped at
1143 * a page size and will be chained together if required. See the
1144 * theory statement for more information.
1145 */
1146 ret = mac_maxsdu_update(igc->igc_mac_hdl, mtu);
1147 if (ret == 0) {
1148 igc->igc_mtu = mtu;
1149 igc_hw_buf_update(igc);
1150 }
1151 break;
1152 case MAC_PROP_FLOWCTRL:
1153 bcopy(val, &fc, sizeof (uint32_t));
1154
1155 switch (fc) {
1156 case LINK_FLOWCTRL_NONE:
1157 igc->igc_hw.fc.requested_mode = igc_fc_none;
1158 break;
1159 case LINK_FLOWCTRL_RX:
1160 igc->igc_hw.fc.requested_mode = igc_fc_rx_pause;
1161 break;
1162 case LINK_FLOWCTRL_TX:
1163 igc->igc_hw.fc.requested_mode = igc_fc_tx_pause;
1164 break;
1165 case LINK_FLOWCTRL_BI:
1166 igc->igc_hw.fc.requested_mode = igc_fc_full;
1167 break;
1168 default:
1169 ret = EINVAL;
1170 break;
1171 }
1172 break;
1173 case MAC_PROP_EN_2500FDX_CAP:
1174 bcopy(val, &en, sizeof (uint8_t));
1175 if (en != 0) {
1176 igc->igc_hw.phy.autoneg_advertised |=
1177 ADVERTISE_2500_FULL;
1178 } else {
1179 igc->igc_hw.phy.autoneg_advertised &=
1180 ~ADVERTISE_2500_FULL;
1181 }
1182 break;
1183 case MAC_PROP_EN_1000FDX_CAP:
1184 bcopy(val, &en, sizeof (uint8_t));
1185 if (en != 0) {
1186 igc->igc_hw.phy.autoneg_advertised |=
1187 ADVERTISE_1000_FULL;
1188 } else {
1189 igc->igc_hw.phy.autoneg_advertised &=
1190 ~ADVERTISE_1000_FULL;
1191 }
1192 break;
1193 case MAC_PROP_EN_100FDX_CAP:
1194 bcopy(val, &en, sizeof (uint8_t));
1195 if (en != 0) {
1196 igc->igc_hw.phy.autoneg_advertised |=
1197 ADVERTISE_100_FULL;
1198 } else {
1199 igc->igc_hw.phy.autoneg_advertised &=
1200 ~ADVERTISE_100_FULL;
1201 }
1202 break;
1203 case MAC_PROP_EN_100HDX_CAP:
1204 bcopy(val, &en, sizeof (uint8_t));
1205 if (en != 0) {
1206 igc->igc_hw.phy.autoneg_advertised |=
1207 ADVERTISE_100_HALF;
1208 } else {
1209 igc->igc_hw.phy.autoneg_advertised &=
1210 ~ADVERTISE_100_HALF;
1211 }
1212 break;
1213 case MAC_PROP_EN_10FDX_CAP:
1214 bcopy(val, &en, sizeof (uint8_t));
1215 if (en != 0) {
1216 igc->igc_hw.phy.autoneg_advertised |=
1217 ADVERTISE_10_FULL;
1218 } else {
1219 igc->igc_hw.phy.autoneg_advertised &=
1220 ~ADVERTISE_10_FULL;
1221 }
1222 break;
1223 case MAC_PROP_EN_10HDX_CAP:
1224 bcopy(val, &en, sizeof (uint8_t));
1225 if (en != 0) {
1226 igc->igc_hw.phy.autoneg_advertised |=
1227 ADVERTISE_10_HALF;
1228 } else {
1229 igc->igc_hw.phy.autoneg_advertised &=
1230 ~ADVERTISE_10_HALF;
1231 }
1232 break;
1233 default:
1234 ret = ENOTSUP;
1235 break;
1236 }
1237
1238 if (ret == 0 && update_link) {
1239 if (igc_setup_link(&igc->igc_hw) != IGC_SUCCESS) {
1240 ret = EIO;
1241 }
1242 }
1243 mutex_exit(&igc->igc_lock);
1244
1245 return (ret);
1246 }
1247
1248 static mac_callbacks_t igc_mac_callbacks = {
1249 .mc_callbacks = MC_GETCAPAB | MC_GETPROP | MC_SETPROP | MC_PROPINFO,
1250 .mc_getstat = igc_m_getstat,
1251 .mc_start = igc_m_start,
1252 .mc_stop = igc_m_stop,
1253 .mc_setpromisc = igc_m_setpromisc,
1254 .mc_multicst = igc_m_multicast,
1255 .mc_getcapab = igc_m_getcapab,
1256 .mc_setprop = igc_m_setprop,
1257 .mc_getprop = igc_m_getprop,
1258 .mc_propinfo = igc_m_propinfo
1259 };
1260
1261 bool
igc_mac_register(igc_t * igc)1262 igc_mac_register(igc_t *igc)
1263 {
1264 int ret;
1265 mac_register_t *mac = mac_alloc(MAC_VERSION);
1266
1267 if (mac == NULL) {
1268 dev_err(igc->igc_dip, CE_WARN, "failed to allocate mac "
1269 "registration handle");
1270 return (false);
1271 }
1272
1273 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1274 mac->m_driver = igc;
1275 mac->m_dip = igc->igc_dip;
1276 mac->m_src_addr = igc->igc_hw.mac.addr;
1277 mac->m_callbacks = &igc_mac_callbacks;
1278 mac->m_min_sdu = 0;
1279 mac->m_max_sdu = igc->igc_mtu;
1280 mac->m_margin = VLAN_TAGSZ;
1281 mac->m_priv_props = NULL;
1282 mac->m_v12n = MAC_VIRT_LEVEL1;
1283
1284 ret = mac_register(mac, &igc->igc_mac_hdl);
1285 mac_free(mac);
1286 if (ret != 0) {
1287 dev_err(igc->igc_dip, CE_WARN, "failed to register with MAC: "
1288 "%d", ret);
1289 return (false);
1290 }
1291
1292 return (true);
1293 }
1294