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