xref: /illumos-gate/usr/src/uts/common/io/ixgbe/ixgbe_gld.c (revision a2de976fd11ced5331ebe7c3a8ffbaf11f5427cf)
1 /*
2  * CDDL HEADER START
3  *
4  * Copyright(c) 2007-2009 Intel Corporation. All rights reserved.
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #include "ixgbe_sw.h"
29 
30 /*
31  * Retrieve a value for one of the statistics.
32  */
33 int
34 ixgbe_m_stat(void *arg, uint_t stat, uint64_t *val)
35 {
36 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
37 	struct ixgbe_hw *hw = &ixgbe->hw;
38 	ixgbe_stat_t *ixgbe_ks;
39 	int i;
40 
41 	ixgbe_ks = (ixgbe_stat_t *)ixgbe->ixgbe_ks->ks_data;
42 
43 	mutex_enter(&ixgbe->gen_lock);
44 
45 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
46 		mutex_exit(&ixgbe->gen_lock);
47 		return (ECANCELED);
48 	}
49 
50 	switch (stat) {
51 	case MAC_STAT_IFSPEED:
52 		*val = ixgbe->link_speed * 1000000ull;
53 		break;
54 
55 	case MAC_STAT_MULTIRCV:
56 		ixgbe_ks->mprc.value.ui64 +=
57 		    IXGBE_READ_REG(hw, IXGBE_MPRC);
58 		*val = ixgbe_ks->mprc.value.ui64;
59 		break;
60 
61 	case MAC_STAT_BRDCSTRCV:
62 		ixgbe_ks->bprc.value.ui64 +=
63 		    IXGBE_READ_REG(hw, IXGBE_BPRC);
64 		*val = ixgbe_ks->bprc.value.ui64;
65 		break;
66 
67 	case MAC_STAT_MULTIXMT:
68 		ixgbe_ks->mptc.value.ui64 +=
69 		    IXGBE_READ_REG(hw, IXGBE_MPTC);
70 		*val = ixgbe_ks->mptc.value.ui64;
71 		break;
72 
73 	case MAC_STAT_BRDCSTXMT:
74 		ixgbe_ks->bptc.value.ui64 +=
75 		    IXGBE_READ_REG(hw, IXGBE_BPTC);
76 		*val = ixgbe_ks->bptc.value.ui64;
77 		break;
78 
79 	case MAC_STAT_NORCVBUF:
80 		for (i = 0; i < 8; i++) {
81 			ixgbe_ks->rnbc.value.ui64 +=
82 			    IXGBE_READ_REG(hw, IXGBE_RNBC(i));
83 		}
84 		*val = ixgbe_ks->rnbc.value.ui64;
85 		break;
86 
87 	case MAC_STAT_IERRORS:
88 		ixgbe_ks->crcerrs.value.ui64 +=
89 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
90 		ixgbe_ks->illerrc.value.ui64 +=
91 		    IXGBE_READ_REG(hw, IXGBE_ILLERRC);
92 		ixgbe_ks->errbc.value.ui64 +=
93 		    IXGBE_READ_REG(hw, IXGBE_ERRBC);
94 		ixgbe_ks->rlec.value.ui64 +=
95 		    IXGBE_READ_REG(hw, IXGBE_RLEC);
96 		*val = ixgbe_ks->crcerrs.value.ui64 +
97 		    ixgbe_ks->illerrc.value.ui64 +
98 		    ixgbe_ks->errbc.value.ui64 +
99 		    ixgbe_ks->rlec.value.ui64;
100 		break;
101 
102 	case MAC_STAT_RBYTES:
103 		ixgbe_ks->tor.value.ui64 = 0;
104 		for (i = 0; i < 16; i++) {
105 			ixgbe_ks->qbrc[i].value.ui64 +=
106 			    IXGBE_READ_REG(hw, IXGBE_QBRC(i));
107 			ixgbe_ks->tor.value.ui64 +=
108 			    ixgbe_ks->qbrc[i].value.ui64;
109 		}
110 		*val = ixgbe_ks->tor.value.ui64;
111 		break;
112 
113 	case MAC_STAT_OBYTES:
114 		ixgbe_ks->tot.value.ui64 = 0;
115 		for (i = 0; i < 16; i++) {
116 			if (hw->mac.type >= ixgbe_mac_82599EB) {
117 				ixgbe_ks->qbtc[i].value.ui64 +=
118 				    IXGBE_READ_REG(hw, IXGBE_QBTC_L(i));
119 				ixgbe_ks->qbtc[i].value.ui64 += ((uint64_t)
120 				    IXGBE_READ_REG(hw, IXGBE_QBTC_H(i))) << 32;
121 			} else {
122 				ixgbe_ks->qbtc[i].value.ui64 +=
123 				    IXGBE_READ_REG(hw, IXGBE_QBTC(i));
124 			}
125 			ixgbe_ks->tot.value.ui64 +=
126 			    ixgbe_ks->qbtc[i].value.ui64;
127 		}
128 		*val = ixgbe_ks->tot.value.ui64;
129 		break;
130 
131 	case MAC_STAT_IPACKETS:
132 		ixgbe_ks->tpr.value.ui64 +=
133 		    IXGBE_READ_REG(hw, IXGBE_TPR);
134 		*val = ixgbe_ks->tpr.value.ui64;
135 		break;
136 
137 	case MAC_STAT_OPACKETS:
138 		ixgbe_ks->tpt.value.ui64 +=
139 		    IXGBE_READ_REG(hw, IXGBE_TPT);
140 		*val = ixgbe_ks->tpt.value.ui64;
141 		break;
142 
143 	/* RFC 1643 stats */
144 	case ETHER_STAT_FCS_ERRORS:
145 		ixgbe_ks->crcerrs.value.ui64 +=
146 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
147 		*val = ixgbe_ks->crcerrs.value.ui64;
148 		break;
149 
150 	case ETHER_STAT_TOOLONG_ERRORS:
151 		ixgbe_ks->roc.value.ui64 +=
152 		    IXGBE_READ_REG(hw, IXGBE_ROC);
153 		*val = ixgbe_ks->roc.value.ui64;
154 		break;
155 
156 	case ETHER_STAT_MACRCV_ERRORS:
157 		ixgbe_ks->crcerrs.value.ui64 +=
158 		    IXGBE_READ_REG(hw, IXGBE_CRCERRS);
159 		ixgbe_ks->illerrc.value.ui64 +=
160 		    IXGBE_READ_REG(hw, IXGBE_ILLERRC);
161 		ixgbe_ks->errbc.value.ui64 +=
162 		    IXGBE_READ_REG(hw, IXGBE_ERRBC);
163 		ixgbe_ks->rlec.value.ui64 +=
164 		    IXGBE_READ_REG(hw, IXGBE_RLEC);
165 		*val = ixgbe_ks->crcerrs.value.ui64 +
166 		    ixgbe_ks->illerrc.value.ui64 +
167 		    ixgbe_ks->errbc.value.ui64 +
168 		    ixgbe_ks->rlec.value.ui64;
169 		break;
170 
171 	/* MII/GMII stats */
172 	case ETHER_STAT_XCVR_ADDR:
173 		/* The Internal PHY's MDI address for each MAC is 1 */
174 		*val = 1;
175 		break;
176 
177 	case ETHER_STAT_XCVR_ID:
178 		*val = hw->phy.id;
179 		break;
180 
181 	case ETHER_STAT_XCVR_INUSE:
182 		switch (ixgbe->link_speed) {
183 		case IXGBE_LINK_SPEED_1GB_FULL:
184 			*val =
185 			    (hw->phy.media_type == ixgbe_media_type_copper) ?
186 			    XCVR_1000T : XCVR_1000X;
187 			break;
188 		case IXGBE_LINK_SPEED_100_FULL:
189 			*val = (hw->phy.media_type == ixgbe_media_type_copper) ?
190 			    XCVR_100T2 : XCVR_100X;
191 			break;
192 		default:
193 			*val = XCVR_NONE;
194 			break;
195 		}
196 		break;
197 
198 	case ETHER_STAT_CAP_10GFDX:
199 		*val = 1;
200 		break;
201 
202 	case ETHER_STAT_CAP_1000FDX:
203 		*val = 1;
204 		break;
205 
206 	case ETHER_STAT_CAP_100FDX:
207 		*val = 1;
208 		break;
209 
210 	case ETHER_STAT_CAP_ASMPAUSE:
211 		*val = ixgbe->param_asym_pause_cap;
212 		break;
213 
214 	case ETHER_STAT_CAP_PAUSE:
215 		*val = ixgbe->param_pause_cap;
216 		break;
217 
218 	case ETHER_STAT_CAP_AUTONEG:
219 		*val = 1;
220 		break;
221 
222 	case ETHER_STAT_ADV_CAP_10GFDX:
223 		*val = ixgbe->param_adv_10000fdx_cap;
224 		break;
225 
226 	case ETHER_STAT_ADV_CAP_1000FDX:
227 		*val = ixgbe->param_adv_1000fdx_cap;
228 		break;
229 
230 	case ETHER_STAT_ADV_CAP_100FDX:
231 		*val = ixgbe->param_adv_100fdx_cap;
232 		break;
233 
234 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
235 		*val = ixgbe->param_adv_asym_pause_cap;
236 		break;
237 
238 	case ETHER_STAT_ADV_CAP_PAUSE:
239 		*val = ixgbe->param_adv_pause_cap;
240 		break;
241 
242 	case ETHER_STAT_ADV_CAP_AUTONEG:
243 		*val = ixgbe->param_adv_autoneg_cap;
244 		break;
245 
246 	case ETHER_STAT_LP_CAP_10GFDX:
247 		*val = ixgbe->param_lp_10000fdx_cap;
248 		break;
249 
250 	case ETHER_STAT_LP_CAP_1000FDX:
251 		*val = ixgbe->param_lp_1000fdx_cap;
252 		break;
253 
254 	case ETHER_STAT_LP_CAP_100FDX:
255 		*val = ixgbe->param_lp_100fdx_cap;
256 		break;
257 
258 	case ETHER_STAT_LP_CAP_ASMPAUSE:
259 		*val = ixgbe->param_lp_asym_pause_cap;
260 		break;
261 
262 	case ETHER_STAT_LP_CAP_PAUSE:
263 		*val = ixgbe->param_lp_pause_cap;
264 		break;
265 
266 	case ETHER_STAT_LP_CAP_AUTONEG:
267 		*val = ixgbe->param_lp_autoneg_cap;
268 		break;
269 
270 	case ETHER_STAT_LINK_ASMPAUSE:
271 		*val = ixgbe->param_asym_pause_cap;
272 		break;
273 
274 	case ETHER_STAT_LINK_PAUSE:
275 		*val = ixgbe->param_pause_cap;
276 		break;
277 
278 	case ETHER_STAT_LINK_AUTONEG:
279 		*val = ixgbe->param_adv_autoneg_cap;
280 		break;
281 
282 	case ETHER_STAT_LINK_DUPLEX:
283 		*val = LINK_DUPLEX_FULL;
284 		break;
285 
286 	case ETHER_STAT_TOOSHORT_ERRORS:
287 		ixgbe_ks->ruc.value.ui64 +=
288 		    IXGBE_READ_REG(hw, IXGBE_RUC);
289 		*val = ixgbe_ks->ruc.value.ui64;
290 		break;
291 
292 	case ETHER_STAT_CAP_REMFAULT:
293 		*val = ixgbe->param_rem_fault;
294 		break;
295 
296 	case ETHER_STAT_ADV_REMFAULT:
297 		*val = ixgbe->param_adv_rem_fault;
298 		break;
299 
300 	case ETHER_STAT_LP_REMFAULT:
301 		*val = ixgbe->param_lp_rem_fault;
302 		break;
303 
304 	case ETHER_STAT_JABBER_ERRORS:
305 		ixgbe_ks->rjc.value.ui64 +=
306 		    IXGBE_READ_REG(hw, IXGBE_RJC);
307 		*val = ixgbe_ks->rjc.value.ui64;
308 		break;
309 
310 	default:
311 		mutex_exit(&ixgbe->gen_lock);
312 		return (ENOTSUP);
313 	}
314 
315 	mutex_exit(&ixgbe->gen_lock);
316 
317 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK)
318 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_UNAFFECTED);
319 
320 	return (0);
321 }
322 
323 /*
324  * Bring the device out of the reset/quiesced state that it
325  * was in when the interface was registered.
326  */
327 int
328 ixgbe_m_start(void *arg)
329 {
330 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
331 
332 	mutex_enter(&ixgbe->gen_lock);
333 
334 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
335 		mutex_exit(&ixgbe->gen_lock);
336 		return (ECANCELED);
337 	}
338 
339 	if (ixgbe_start(ixgbe, B_TRUE) != IXGBE_SUCCESS) {
340 		mutex_exit(&ixgbe->gen_lock);
341 		return (EIO);
342 	}
343 
344 	ixgbe->ixgbe_state |= IXGBE_STARTED;
345 
346 	mutex_exit(&ixgbe->gen_lock);
347 
348 	/*
349 	 * Enable and start the watchdog timer
350 	 */
351 	ixgbe_enable_watchdog_timer(ixgbe);
352 
353 	return (0);
354 }
355 
356 /*
357  * Stop the device and put it in a reset/quiesced state such
358  * that the interface can be unregistered.
359  */
360 void
361 ixgbe_m_stop(void *arg)
362 {
363 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
364 
365 	mutex_enter(&ixgbe->gen_lock);
366 
367 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
368 		mutex_exit(&ixgbe->gen_lock);
369 		return;
370 	}
371 
372 	ixgbe->ixgbe_state &= ~IXGBE_STARTED;
373 
374 	ixgbe_stop(ixgbe, B_TRUE);
375 
376 	mutex_exit(&ixgbe->gen_lock);
377 
378 	/*
379 	 * Disable and stop the watchdog timer
380 	 */
381 	ixgbe_disable_watchdog_timer(ixgbe);
382 }
383 
384 /*
385  * Set the promiscuity of the device.
386  */
387 int
388 ixgbe_m_promisc(void *arg, boolean_t on)
389 {
390 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
391 	uint32_t reg_val;
392 	struct ixgbe_hw *hw = &ixgbe->hw;
393 
394 	mutex_enter(&ixgbe->gen_lock);
395 
396 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
397 		mutex_exit(&ixgbe->gen_lock);
398 		return (ECANCELED);
399 	}
400 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
401 
402 	if (on)
403 		reg_val |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
404 	else
405 		reg_val &= (~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE));
406 
407 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_FCTRL, reg_val);
408 
409 	mutex_exit(&ixgbe->gen_lock);
410 
411 	return (0);
412 }
413 
414 /*
415  * Add/remove the addresses to/from the set of multicast
416  * addresses for which the device will receive packets.
417  */
418 int
419 ixgbe_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
420 {
421 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
422 	int result;
423 
424 	mutex_enter(&ixgbe->gen_lock);
425 
426 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
427 		mutex_exit(&ixgbe->gen_lock);
428 		return (ECANCELED);
429 	}
430 
431 	result = (add) ? ixgbe_multicst_add(ixgbe, mcst_addr)
432 	    : ixgbe_multicst_remove(ixgbe, mcst_addr);
433 
434 	mutex_exit(&ixgbe->gen_lock);
435 
436 	return (result);
437 }
438 
439 /*
440  * Pass on M_IOCTL messages passed to the DLD, and support
441  * private IOCTLs for debugging and ndd.
442  */
443 void
444 ixgbe_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
445 {
446 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
447 	struct iocblk *iocp;
448 	enum ioc_reply status;
449 
450 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
451 	iocp->ioc_error = 0;
452 
453 	mutex_enter(&ixgbe->gen_lock);
454 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
455 		mutex_exit(&ixgbe->gen_lock);
456 		miocnak(q, mp, 0, EINVAL);
457 		return;
458 	}
459 	mutex_exit(&ixgbe->gen_lock);
460 
461 	switch (iocp->ioc_cmd) {
462 	case LB_GET_INFO_SIZE:
463 	case LB_GET_INFO:
464 	case LB_GET_MODE:
465 	case LB_SET_MODE:
466 		status = ixgbe_loopback_ioctl(ixgbe, iocp, mp);
467 		break;
468 
469 	default:
470 		status = IOC_INVAL;
471 		break;
472 	}
473 
474 	/*
475 	 * Decide how to reply
476 	 */
477 	switch (status) {
478 	default:
479 	case IOC_INVAL:
480 		/*
481 		 * Error, reply with a NAK and EINVAL or the specified error
482 		 */
483 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
484 		    EINVAL : iocp->ioc_error);
485 		break;
486 
487 	case IOC_DONE:
488 		/*
489 		 * OK, reply already sent
490 		 */
491 		break;
492 
493 	case IOC_ACK:
494 		/*
495 		 * OK, reply with an ACK
496 		 */
497 		miocack(q, mp, 0, 0);
498 		break;
499 
500 	case IOC_REPLY:
501 		/*
502 		 * OK, send prepared reply as ACK or NAK
503 		 */
504 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
505 		    M_IOCACK : M_IOCNAK;
506 		qreply(q, mp);
507 		break;
508 	}
509 }
510 
511 /*
512  * Obtain the MAC's capabilities and associated data from
513  * the driver.
514  */
515 boolean_t
516 ixgbe_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
517 {
518 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
519 
520 	switch (cap) {
521 	case MAC_CAPAB_HCKSUM: {
522 		uint32_t *tx_hcksum_flags = cap_data;
523 
524 		/*
525 		 * We advertise our capabilities only if tx hcksum offload is
526 		 * enabled.  On receive, the stack will accept checksummed
527 		 * packets anyway, even if we haven't said we can deliver
528 		 * them.
529 		 */
530 		if (!ixgbe->tx_hcksum_enable)
531 			return (B_FALSE);
532 
533 		*tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
534 		break;
535 	}
536 	case MAC_CAPAB_LSO: {
537 		mac_capab_lso_t *cap_lso = cap_data;
538 
539 		if (ixgbe->lso_enable) {
540 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
541 			cap_lso->lso_basic_tcp_ipv4.lso_max = IXGBE_LSO_MAXLEN;
542 			break;
543 		} else {
544 			return (B_FALSE);
545 		}
546 	}
547 	case MAC_CAPAB_RINGS: {
548 		mac_capab_rings_t *cap_rings = cap_data;
549 
550 		switch (cap_rings->mr_type) {
551 		case MAC_RING_TYPE_RX:
552 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
553 			cap_rings->mr_rnum = ixgbe->num_rx_rings;
554 			cap_rings->mr_gnum = ixgbe->num_rx_groups;
555 			cap_rings->mr_rget = ixgbe_fill_ring;
556 			cap_rings->mr_gget = ixgbe_fill_group;
557 			cap_rings->mr_gaddring = NULL;
558 			cap_rings->mr_gremring = NULL;
559 			break;
560 		case MAC_RING_TYPE_TX:
561 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
562 			cap_rings->mr_rnum = ixgbe->num_tx_rings;
563 			cap_rings->mr_gnum = 0;
564 			cap_rings->mr_rget = ixgbe_fill_ring;
565 			cap_rings->mr_gget = NULL;
566 			break;
567 		default:
568 			break;
569 		}
570 		break;
571 	}
572 	default:
573 		return (B_FALSE);
574 	}
575 	return (B_TRUE);
576 }
577 
578 int
579 ixgbe_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
580     uint_t pr_valsize, const void *pr_val)
581 {
582 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
583 	struct ixgbe_hw *hw = &ixgbe->hw;
584 	int err = 0;
585 	uint32_t flow_control;
586 	uint32_t cur_mtu, new_mtu;
587 	uint32_t rx_size;
588 	uint32_t tx_size;
589 
590 	mutex_enter(&ixgbe->gen_lock);
591 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
592 		mutex_exit(&ixgbe->gen_lock);
593 		return (ECANCELED);
594 	}
595 
596 	if (ixgbe->loopback_mode != IXGBE_LB_NONE &&
597 	    ixgbe_param_locked(pr_num)) {
598 		/*
599 		 * All en_* parameters are locked (read-only)
600 		 * while the device is in any sort of loopback mode.
601 		 */
602 		mutex_exit(&ixgbe->gen_lock);
603 		return (EBUSY);
604 	}
605 
606 	switch (pr_num) {
607 	case MAC_PROP_EN_10GFDX_CAP:
608 		/* read/write on copper, read-only on serdes */
609 		if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
610 			err = ENOTSUP;
611 			break;
612 		} else {
613 			ixgbe->param_en_10000fdx_cap = *(uint8_t *)pr_val;
614 			ixgbe->param_adv_10000fdx_cap = *(uint8_t *)pr_val;
615 			goto setup_link;
616 		}
617 	case MAC_PROP_EN_1000FDX_CAP:
618 		/* read/write on copper, read-only on serdes */
619 		if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
620 			err = ENOTSUP;
621 			break;
622 		} else {
623 			ixgbe->param_en_1000fdx_cap = *(uint8_t *)pr_val;
624 			ixgbe->param_adv_1000fdx_cap = *(uint8_t *)pr_val;
625 			goto setup_link;
626 		}
627 	case MAC_PROP_EN_100FDX_CAP:
628 		/* read/write on copper, read-only on serdes */
629 		if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
630 			err = ENOTSUP;
631 			break;
632 		} else {
633 			ixgbe->param_en_100fdx_cap = *(uint8_t *)pr_val;
634 			ixgbe->param_adv_100fdx_cap = *(uint8_t *)pr_val;
635 			goto setup_link;
636 		}
637 	case MAC_PROP_AUTONEG:
638 		/* read/write on copper, read-only on serdes */
639 		if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
640 			err = ENOTSUP;
641 			break;
642 		} else {
643 			ixgbe->param_adv_autoneg_cap = *(uint8_t *)pr_val;
644 			goto setup_link;
645 		}
646 	case MAC_PROP_FLOWCTRL:
647 		bcopy(pr_val, &flow_control, sizeof (flow_control));
648 
649 		switch (flow_control) {
650 		default:
651 			err = EINVAL;
652 			break;
653 		case LINK_FLOWCTRL_NONE:
654 			hw->fc.requested_mode = ixgbe_fc_none;
655 			break;
656 		case LINK_FLOWCTRL_RX:
657 			hw->fc.requested_mode = ixgbe_fc_rx_pause;
658 			break;
659 		case LINK_FLOWCTRL_TX:
660 			hw->fc.requested_mode = ixgbe_fc_tx_pause;
661 			break;
662 		case LINK_FLOWCTRL_BI:
663 			hw->fc.requested_mode = ixgbe_fc_full;
664 			break;
665 		}
666 setup_link:
667 		if (err == 0) {
668 			if (ixgbe_driver_setup_link(ixgbe, B_TRUE) !=
669 			    IXGBE_SUCCESS)
670 				err = EINVAL;
671 		}
672 		break;
673 	case MAC_PROP_ADV_10GFDX_CAP:
674 	case MAC_PROP_ADV_1000FDX_CAP:
675 	case MAC_PROP_ADV_100FDX_CAP:
676 	case MAC_PROP_STATUS:
677 	case MAC_PROP_SPEED:
678 	case MAC_PROP_DUPLEX:
679 		err = ENOTSUP; /* read-only prop. Can't set this. */
680 		break;
681 	case MAC_PROP_MTU:
682 		cur_mtu = ixgbe->default_mtu;
683 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
684 		if (new_mtu == cur_mtu) {
685 			err = 0;
686 			break;
687 		}
688 
689 		if (new_mtu < DEFAULT_MTU || new_mtu > MAX_MTU) {
690 			err = EINVAL;
691 			break;
692 		}
693 
694 		if (ixgbe->ixgbe_state & IXGBE_STARTED) {
695 			err = EBUSY;
696 			break;
697 		}
698 
699 		err = mac_maxsdu_update(ixgbe->mac_hdl, new_mtu);
700 		if (err == 0) {
701 			ixgbe->default_mtu = new_mtu;
702 			ixgbe->max_frame_size = ixgbe->default_mtu +
703 			    sizeof (struct ether_vlan_header) + ETHERFCSL;
704 
705 			/*
706 			 * Set rx buffer size
707 			 */
708 			rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
709 			ixgbe->rx_buf_size = ((rx_size >> 10) + ((rx_size &
710 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
711 
712 			/*
713 			 * Set tx buffer size
714 			 */
715 			tx_size = ixgbe->max_frame_size;
716 			ixgbe->tx_buf_size = ((tx_size >> 10) + ((tx_size &
717 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
718 		}
719 		break;
720 	case MAC_PROP_PRIVATE:
721 		err = ixgbe_set_priv_prop(ixgbe, pr_name, pr_valsize, pr_val);
722 		break;
723 	default:
724 		err = EINVAL;
725 		break;
726 	}
727 	mutex_exit(&ixgbe->gen_lock);
728 	return (err);
729 }
730 
731 int
732 ixgbe_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
733     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
734 {
735 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
736 	struct ixgbe_hw *hw = &ixgbe->hw;
737 	int err = 0;
738 	uint32_t flow_control;
739 	uint64_t tmp = 0;
740 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
741 	mac_propval_range_t range;
742 
743 	if (pr_valsize == 0)
744 		return (EINVAL);
745 
746 	*perm = MAC_PROP_PERM_READ;
747 
748 	bzero(pr_val, pr_valsize);
749 
750 	switch (pr_num) {
751 	case MAC_PROP_DUPLEX:
752 		if (pr_valsize >= sizeof (link_duplex_t)) {
753 			bcopy(&ixgbe->link_duplex, pr_val,
754 			    sizeof (link_duplex_t));
755 		} else
756 			err = EINVAL;
757 		break;
758 	case MAC_PROP_SPEED:
759 		if (pr_valsize >= sizeof (uint64_t)) {
760 			tmp = ixgbe->link_speed * 1000000ull;
761 			bcopy(&tmp, pr_val, sizeof (tmp));
762 		} else
763 			err = EINVAL;
764 		break;
765 	case MAC_PROP_AUTONEG:
766 		if (ixgbe->hw.phy.media_type == ixgbe_media_type_copper)
767 			*perm = MAC_PROP_PERM_RW;
768 		*(uint8_t *)pr_val =
769 		    (is_default ? 1 : ixgbe->param_adv_autoneg_cap);
770 		break;
771 	case MAC_PROP_FLOWCTRL:
772 		*perm = MAC_PROP_PERM_RW;
773 		if (pr_valsize >= sizeof (uint32_t)) {
774 			if (is_default) {
775 				flow_control = LINK_FLOWCTRL_NONE;
776 				bcopy(&flow_control, pr_val,
777 				    sizeof (flow_control));
778 				break;
779 			}
780 			switch (hw->fc.requested_mode) {
781 				case ixgbe_fc_none:
782 					flow_control = LINK_FLOWCTRL_NONE;
783 					break;
784 				case ixgbe_fc_rx_pause:
785 					flow_control = LINK_FLOWCTRL_RX;
786 					break;
787 				case ixgbe_fc_tx_pause:
788 					flow_control = LINK_FLOWCTRL_TX;
789 					break;
790 				case ixgbe_fc_full:
791 					flow_control = LINK_FLOWCTRL_BI;
792 					break;
793 			}
794 			bcopy(&flow_control, pr_val, sizeof (flow_control));
795 		} else
796 			err = EINVAL;
797 		break;
798 	case MAC_PROP_ADV_10GFDX_CAP:
799 		*(uint8_t *)pr_val = (is_default ? 1 :
800 		    ixgbe->param_adv_10000fdx_cap);
801 		break;
802 	case MAC_PROP_EN_10GFDX_CAP:
803 		if (ixgbe->hw.phy.media_type == ixgbe_media_type_copper)
804 			*perm = MAC_PROP_PERM_RW;
805 		*(uint8_t *)pr_val =
806 		    (is_default ? 1 : ixgbe->param_en_10000fdx_cap);
807 		break;
808 	case MAC_PROP_ADV_1000FDX_CAP:
809 		*(uint8_t *)pr_val = (is_default ? 1 :
810 		    ixgbe->param_adv_1000fdx_cap);
811 		break;
812 	case MAC_PROP_EN_1000FDX_CAP:
813 		if (ixgbe->hw.phy.media_type == ixgbe_media_type_copper)
814 			*perm = MAC_PROP_PERM_RW;
815 		*(uint8_t *)pr_val =
816 		    (is_default ? 1 : ixgbe->param_en_1000fdx_cap);
817 		break;
818 	case MAC_PROP_ADV_100FDX_CAP:
819 		*(uint8_t *)pr_val =
820 		    (is_default ? 1 : ixgbe->param_adv_100fdx_cap);
821 		break;
822 	case MAC_PROP_EN_100FDX_CAP:
823 		if (ixgbe->hw.phy.media_type == ixgbe_media_type_copper)
824 			*perm = MAC_PROP_PERM_RW;
825 		*(uint8_t *)pr_val =
826 		    (is_default ? 1 : ixgbe->param_en_100fdx_cap);
827 		break;
828 	case MAC_PROP_PRIVATE:
829 		err = ixgbe_get_priv_prop(ixgbe, pr_name,
830 		    pr_flags, pr_valsize, pr_val, perm);
831 		break;
832 	case MAC_PROP_MTU:
833 		if (!(pr_flags & MAC_PROP_POSSIBLE))
834 			return (ENOTSUP);
835 		if (pr_valsize < sizeof (mac_propval_range_t))
836 			return (EINVAL);
837 		range.mpr_count = 1;
838 		range.mpr_type = MAC_PROPVAL_UINT32;
839 		range.range_uint32[0].mpur_min = DEFAULT_MTU;
840 		range.range_uint32[0].mpur_max = MAX_MTU;
841 		bcopy(&range, pr_val, sizeof (range));
842 		break;
843 	default:
844 		err = EINVAL;
845 		break;
846 	}
847 	return (err);
848 }
849 
850 boolean_t
851 ixgbe_param_locked(mac_prop_id_t pr_num)
852 {
853 	/*
854 	 * All en_* parameters are locked (read-only) while
855 	 * the device is in any sort of loopback mode ...
856 	 */
857 	switch (pr_num) {
858 		case MAC_PROP_EN_10GFDX_CAP:
859 		case MAC_PROP_EN_1000FDX_CAP:
860 		case MAC_PROP_EN_100FDX_CAP:
861 		case MAC_PROP_AUTONEG:
862 		case MAC_PROP_FLOWCTRL:
863 			return (B_TRUE);
864 	}
865 	return (B_FALSE);
866 }
867 
868 /* ARGSUSED */
869 int
870 ixgbe_set_priv_prop(ixgbe_t *ixgbe, const char *pr_name,
871     uint_t pr_valsize, const void *pr_val)
872 {
873 	int err = 0;
874 	long result;
875 	struct ixgbe_hw *hw = &ixgbe->hw;
876 	int i;
877 
878 	if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
879 		if (pr_val == NULL) {
880 			err = EINVAL;
881 			return (err);
882 		}
883 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
884 		if (result < MIN_TX_COPY_THRESHOLD ||
885 		    result > MAX_TX_COPY_THRESHOLD)
886 			err = EINVAL;
887 		else {
888 			ixgbe->tx_copy_thresh = (uint32_t)result;
889 		}
890 		return (err);
891 	}
892 	if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
893 		if (pr_val == NULL) {
894 			err = EINVAL;
895 			return (err);
896 		}
897 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
898 		if (result < MIN_TX_RECYCLE_THRESHOLD ||
899 		    result > MAX_TX_RECYCLE_THRESHOLD)
900 			err = EINVAL;
901 		else {
902 			ixgbe->tx_recycle_thresh = (uint32_t)result;
903 		}
904 		return (err);
905 	}
906 	if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
907 		if (pr_val == NULL) {
908 			err = EINVAL;
909 			return (err);
910 		}
911 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
912 		if (result < MIN_TX_OVERLOAD_THRESHOLD ||
913 		    result > MAX_TX_OVERLOAD_THRESHOLD)
914 			err = EINVAL;
915 		else {
916 			ixgbe->tx_overload_thresh = (uint32_t)result;
917 		}
918 		return (err);
919 	}
920 	if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
921 		if (pr_val == NULL) {
922 			err = EINVAL;
923 			return (err);
924 		}
925 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
926 		if (result < MIN_TX_RESCHED_THRESHOLD ||
927 		    result > MAX_TX_RESCHED_THRESHOLD)
928 			err = EINVAL;
929 		else {
930 			ixgbe->tx_resched_thresh = (uint32_t)result;
931 		}
932 		return (err);
933 	}
934 	if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
935 		if (pr_val == NULL) {
936 			err = EINVAL;
937 			return (err);
938 		}
939 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
940 		if (result < MIN_RX_COPY_THRESHOLD ||
941 		    result > MAX_RX_COPY_THRESHOLD)
942 			err = EINVAL;
943 		else {
944 			ixgbe->rx_copy_thresh = (uint32_t)result;
945 		}
946 		return (err);
947 	}
948 	if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
949 		if (pr_val == NULL) {
950 			err = EINVAL;
951 			return (err);
952 		}
953 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
954 		if (result < MIN_RX_LIMIT_PER_INTR ||
955 		    result > MAX_RX_LIMIT_PER_INTR)
956 			err = EINVAL;
957 		else {
958 			ixgbe->rx_limit_per_intr = (uint32_t)result;
959 		}
960 		return (err);
961 	}
962 	if (strcmp(pr_name, "_intr_throttling") == 0) {
963 		if (pr_val == NULL) {
964 			err = EINVAL;
965 			return (err);
966 		}
967 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
968 
969 		if (result < ixgbe->capab->min_intr_throttle ||
970 		    result > ixgbe->capab->max_intr_throttle)
971 			err = EINVAL;
972 		else {
973 			ixgbe->intr_throttling[0] = (uint32_t)result;
974 
975 			/*
976 			 * 82599 requires the interupt throttling rate is
977 			 * a multiple of 8. This is enforced by the register
978 			 * definiton.
979 			 */
980 			if (hw->mac.type == ixgbe_mac_82599EB)
981 				ixgbe->intr_throttling[0] =
982 				    ixgbe->intr_throttling[0] & 0xFF8;
983 
984 			for (i = 0; i < MAX_INTR_VECTOR; i++)
985 				ixgbe->intr_throttling[i] =
986 				    ixgbe->intr_throttling[0];
987 
988 			/* Set interrupt throttling rate */
989 			for (i = 0; i < ixgbe->intr_cnt; i++)
990 				IXGBE_WRITE_REG(hw, IXGBE_EITR(i),
991 				    ixgbe->intr_throttling[i]);
992 		}
993 		return (err);
994 	}
995 	return (ENOTSUP);
996 }
997 
998 int
999 ixgbe_get_priv_prop(ixgbe_t *ixgbe, const char *pr_name,
1000     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
1001 {
1002 	int err = ENOTSUP;
1003 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
1004 	int value;
1005 
1006 	*perm = MAC_PROP_PERM_RW;
1007 
1008 	if (strcmp(pr_name, "_adv_pause_cap") == 0) {
1009 		*perm = MAC_PROP_PERM_READ;
1010 		value = (is_default ? 1 : ixgbe->param_adv_pause_cap);
1011 		err = 0;
1012 		goto done;
1013 	}
1014 	if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
1015 		*perm = MAC_PROP_PERM_READ;
1016 		value = (is_default ? 1 : ixgbe->param_adv_asym_pause_cap);
1017 		err = 0;
1018 		goto done;
1019 	}
1020 	if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
1021 		value = (is_default ? DEFAULT_TX_COPY_THRESHOLD :
1022 		    ixgbe->tx_copy_thresh);
1023 		err = 0;
1024 		goto done;
1025 	}
1026 	if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
1027 		value = (is_default ? DEFAULT_TX_RECYCLE_THRESHOLD :
1028 		    ixgbe->tx_recycle_thresh);
1029 		err = 0;
1030 		goto done;
1031 	}
1032 	if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
1033 		value = (is_default ? DEFAULT_TX_OVERLOAD_THRESHOLD :
1034 		    ixgbe->tx_overload_thresh);
1035 		err = 0;
1036 		goto done;
1037 	}
1038 	if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
1039 		value = (is_default ? DEFAULT_TX_RESCHED_THRESHOLD :
1040 		    ixgbe->tx_resched_thresh);
1041 		err = 0;
1042 		goto done;
1043 	}
1044 	if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
1045 		value = (is_default ? DEFAULT_RX_COPY_THRESHOLD :
1046 		    ixgbe->rx_copy_thresh);
1047 		err = 0;
1048 		goto done;
1049 	}
1050 	if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
1051 		value = (is_default ? DEFAULT_RX_LIMIT_PER_INTR :
1052 		    ixgbe->rx_limit_per_intr);
1053 		err = 0;
1054 		goto done;
1055 	}
1056 	if (strcmp(pr_name, "_intr_throttling") == 0) {
1057 		value = (is_default ? ixgbe->capab->def_intr_throttle :
1058 		    ixgbe->intr_throttling[0]);
1059 		err = 0;
1060 		goto done;
1061 	}
1062 done:
1063 	if (err == 0) {
1064 		(void) snprintf(pr_val, pr_valsize, "%d", value);
1065 	}
1066 	return (err);
1067 }
1068