xref: /illumos-gate/usr/src/uts/common/io/igc/igc_gld.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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