xref: /illumos-gate/usr/src/uts/common/io/ixgbe/ixgbe_gld.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
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 = hw->mac.autoneg;
280 		break;
281 	case ETHER_STAT_LINK_DUPLEX:
282 		*val = LINK_DUPLEX_FULL;
283 		break;
284 
285 	case ETHER_STAT_TOOSHORT_ERRORS:
286 		ixgbe_ks->ruc.value.ui64 +=
287 		    IXGBE_READ_REG(hw, IXGBE_RUC);
288 		*val = ixgbe_ks->ruc.value.ui64;
289 		break;
290 
291 	case ETHER_STAT_CAP_REMFAULT:
292 		*val = ixgbe->param_rem_fault;
293 		break;
294 
295 	case ETHER_STAT_ADV_REMFAULT:
296 		*val = ixgbe->param_adv_rem_fault;
297 		break;
298 
299 	case ETHER_STAT_LP_REMFAULT:
300 		*val = ixgbe->param_lp_rem_fault;
301 		break;
302 
303 	case ETHER_STAT_JABBER_ERRORS:
304 		ixgbe_ks->rjc.value.ui64 +=
305 		    IXGBE_READ_REG(hw, IXGBE_RJC);
306 		*val = ixgbe_ks->rjc.value.ui64;
307 		break;
308 
309 	default:
310 		mutex_exit(&ixgbe->gen_lock);
311 		return (ENOTSUP);
312 	}
313 
314 	mutex_exit(&ixgbe->gen_lock);
315 
316 	if (ixgbe_check_acc_handle(ixgbe->osdep.reg_handle) != DDI_FM_OK)
317 		ddi_fm_service_impact(ixgbe->dip, DDI_SERVICE_UNAFFECTED);
318 
319 	return (0);
320 }
321 
322 /*
323  * Bring the device out of the reset/quiesced state that it
324  * was in when the interface was registered.
325  */
326 int
327 ixgbe_m_start(void *arg)
328 {
329 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
330 
331 	mutex_enter(&ixgbe->gen_lock);
332 
333 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
334 		mutex_exit(&ixgbe->gen_lock);
335 		return (ECANCELED);
336 	}
337 
338 	if (ixgbe_start(ixgbe, B_TRUE) != IXGBE_SUCCESS) {
339 		mutex_exit(&ixgbe->gen_lock);
340 		return (EIO);
341 	}
342 
343 	ixgbe->ixgbe_state |= IXGBE_STARTED;
344 
345 	mutex_exit(&ixgbe->gen_lock);
346 
347 	/*
348 	 * Enable and start the watchdog timer
349 	 */
350 	ixgbe_enable_watchdog_timer(ixgbe);
351 
352 	return (0);
353 }
354 
355 /*
356  * Stop the device and put it in a reset/quiesced state such
357  * that the interface can be unregistered.
358  */
359 void
360 ixgbe_m_stop(void *arg)
361 {
362 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
363 
364 	mutex_enter(&ixgbe->gen_lock);
365 
366 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
367 		mutex_exit(&ixgbe->gen_lock);
368 		return;
369 	}
370 
371 	ixgbe->ixgbe_state &= ~IXGBE_STARTED;
372 
373 	ixgbe_stop(ixgbe, B_TRUE);
374 
375 	mutex_exit(&ixgbe->gen_lock);
376 
377 	/*
378 	 * Disable and stop the watchdog timer
379 	 */
380 	ixgbe_disable_watchdog_timer(ixgbe);
381 }
382 
383 /*
384  * Set the promiscuity of the device.
385  */
386 int
387 ixgbe_m_promisc(void *arg, boolean_t on)
388 {
389 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
390 	uint32_t reg_val;
391 	struct ixgbe_hw *hw = &ixgbe->hw;
392 
393 	mutex_enter(&ixgbe->gen_lock);
394 
395 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
396 		mutex_exit(&ixgbe->gen_lock);
397 		return (ECANCELED);
398 	}
399 	reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
400 
401 	if (on)
402 		reg_val |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
403 	else
404 		reg_val &= (~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE));
405 
406 	IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_FCTRL, reg_val);
407 
408 	mutex_exit(&ixgbe->gen_lock);
409 
410 	return (0);
411 }
412 
413 /*
414  * Add/remove the addresses to/from the set of multicast
415  * addresses for which the device will receive packets.
416  */
417 int
418 ixgbe_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
419 {
420 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
421 	int result;
422 
423 	mutex_enter(&ixgbe->gen_lock);
424 
425 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
426 		mutex_exit(&ixgbe->gen_lock);
427 		return (ECANCELED);
428 	}
429 
430 	result = (add) ? ixgbe_multicst_add(ixgbe, mcst_addr)
431 	    : ixgbe_multicst_remove(ixgbe, mcst_addr);
432 
433 	mutex_exit(&ixgbe->gen_lock);
434 
435 	return (result);
436 }
437 
438 /*
439  * Pass on M_IOCTL messages passed to the DLD, and support
440  * private IOCTLs for debugging and ndd.
441  */
442 void
443 ixgbe_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
444 {
445 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
446 	struct iocblk *iocp;
447 	enum ioc_reply status;
448 
449 	iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
450 	iocp->ioc_error = 0;
451 
452 	mutex_enter(&ixgbe->gen_lock);
453 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
454 		mutex_exit(&ixgbe->gen_lock);
455 		miocnak(q, mp, 0, EINVAL);
456 		return;
457 	}
458 	mutex_exit(&ixgbe->gen_lock);
459 
460 	switch (iocp->ioc_cmd) {
461 	case LB_GET_INFO_SIZE:
462 	case LB_GET_INFO:
463 	case LB_GET_MODE:
464 	case LB_SET_MODE:
465 		status = ixgbe_loopback_ioctl(ixgbe, iocp, mp);
466 		break;
467 
468 	default:
469 		status = IOC_INVAL;
470 		break;
471 	}
472 
473 	/*
474 	 * Decide how to reply
475 	 */
476 	switch (status) {
477 	default:
478 	case IOC_INVAL:
479 		/*
480 		 * Error, reply with a NAK and EINVAL or the specified error
481 		 */
482 		miocnak(q, mp, 0, iocp->ioc_error == 0 ?
483 		    EINVAL : iocp->ioc_error);
484 		break;
485 
486 	case IOC_DONE:
487 		/*
488 		 * OK, reply already sent
489 		 */
490 		break;
491 
492 	case IOC_ACK:
493 		/*
494 		 * OK, reply with an ACK
495 		 */
496 		miocack(q, mp, 0, 0);
497 		break;
498 
499 	case IOC_REPLY:
500 		/*
501 		 * OK, send prepared reply as ACK or NAK
502 		 */
503 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
504 		    M_IOCACK : M_IOCNAK;
505 		qreply(q, mp);
506 		break;
507 	}
508 }
509 
510 /*
511  * Obtain the MAC's capabilities and associated data from
512  * the driver.
513  */
514 boolean_t
515 ixgbe_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
516 {
517 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
518 
519 	switch (cap) {
520 	case MAC_CAPAB_HCKSUM: {
521 		uint32_t *tx_hcksum_flags = cap_data;
522 
523 		/*
524 		 * We advertise our capabilities only if tx hcksum offload is
525 		 * enabled.  On receive, the stack will accept checksummed
526 		 * packets anyway, even if we haven't said we can deliver
527 		 * them.
528 		 */
529 		if (!ixgbe->tx_hcksum_enable)
530 			return (B_FALSE);
531 
532 		*tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
533 		break;
534 	}
535 	case MAC_CAPAB_LSO: {
536 		mac_capab_lso_t *cap_lso = cap_data;
537 
538 		if (ixgbe->lso_enable) {
539 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
540 			cap_lso->lso_basic_tcp_ipv4.lso_max = IXGBE_LSO_MAXLEN;
541 			break;
542 		} else {
543 			return (B_FALSE);
544 		}
545 	}
546 	case MAC_CAPAB_RINGS: {
547 		mac_capab_rings_t *cap_rings = cap_data;
548 
549 		switch (cap_rings->mr_type) {
550 		case MAC_RING_TYPE_RX:
551 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
552 			cap_rings->mr_rnum = ixgbe->num_rx_rings;
553 			cap_rings->mr_gnum = ixgbe->num_rx_groups;
554 			cap_rings->mr_rget = ixgbe_fill_ring;
555 			cap_rings->mr_gget = ixgbe_fill_group;
556 			cap_rings->mr_gaddring = NULL;
557 			cap_rings->mr_gremring = NULL;
558 			break;
559 		case MAC_RING_TYPE_TX:
560 			cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
561 			cap_rings->mr_rnum = ixgbe->num_tx_rings;
562 			cap_rings->mr_gnum = 0;
563 			cap_rings->mr_rget = ixgbe_fill_ring;
564 			cap_rings->mr_gget = NULL;
565 			break;
566 		default:
567 			break;
568 		}
569 		break;
570 	}
571 	default:
572 		return (B_FALSE);
573 	}
574 	return (B_TRUE);
575 }
576 
577 int
578 ixgbe_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
579     uint_t pr_valsize, const void *pr_val)
580 {
581 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
582 	struct ixgbe_hw *hw = &ixgbe->hw;
583 	int err = 0;
584 	uint32_t flow_control;
585 	uint32_t cur_mtu, new_mtu;
586 	uint32_t rx_size;
587 	uint32_t tx_size;
588 
589 	mutex_enter(&ixgbe->gen_lock);
590 	if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
591 		mutex_exit(&ixgbe->gen_lock);
592 		return (ECANCELED);
593 	}
594 
595 	if (ixgbe->loopback_mode != IXGBE_LB_NONE &&
596 	    ixgbe_param_locked(pr_num)) {
597 		/*
598 		 * All en_* parameters are locked (read-only)
599 		 * while the device is in any sort of loopback mode.
600 		 */
601 		mutex_exit(&ixgbe->gen_lock);
602 		return (EBUSY);
603 	}
604 
605 	switch (pr_num) {
606 	case MAC_PROP_EN_10GFDX_CAP:
607 		/* read/write on copper, read-only on serdes */
608 		if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
609 			err = ENOTSUP;
610 			break;
611 		} else {
612 			ixgbe->param_en_10000fdx_cap = *(uint8_t *)pr_val;
613 			ixgbe->param_adv_10000fdx_cap = *(uint8_t *)pr_val;
614 			goto setup_link;
615 		}
616 	case MAC_PROP_EN_1000FDX_CAP:
617 		/* read/write on copper, read-only on serdes */
618 		if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
619 			err = ENOTSUP;
620 			break;
621 		} else {
622 			ixgbe->param_en_1000fdx_cap = *(uint8_t *)pr_val;
623 			ixgbe->param_adv_1000fdx_cap = *(uint8_t *)pr_val;
624 			goto setup_link;
625 		}
626 	case MAC_PROP_EN_100FDX_CAP:
627 		/* read/write on copper, read-only on serdes */
628 		if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
629 			err = ENOTSUP;
630 			break;
631 		} else {
632 			ixgbe->param_en_100fdx_cap = *(uint8_t *)pr_val;
633 			ixgbe->param_adv_100fdx_cap = *(uint8_t *)pr_val;
634 			goto setup_link;
635 		}
636 	case MAC_PROP_AUTONEG:
637 		/* read/write on copper, read-only on serdes */
638 		if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
639 			err = ENOTSUP;
640 			break;
641 		} else {
642 			ixgbe->param_adv_autoneg_cap = *(uint8_t *)pr_val;
643 			goto setup_link;
644 		}
645 	case MAC_PROP_FLOWCTRL:
646 		bcopy(pr_val, &flow_control, sizeof (flow_control));
647 
648 		switch (flow_control) {
649 		default:
650 			err = EINVAL;
651 			break;
652 		case LINK_FLOWCTRL_NONE:
653 			hw->fc.requested_mode = ixgbe_fc_none;
654 			break;
655 		case LINK_FLOWCTRL_RX:
656 			hw->fc.requested_mode = ixgbe_fc_rx_pause;
657 			break;
658 		case LINK_FLOWCTRL_TX:
659 			hw->fc.requested_mode = ixgbe_fc_tx_pause;
660 			break;
661 		case LINK_FLOWCTRL_BI:
662 			hw->fc.requested_mode = ixgbe_fc_full;
663 			break;
664 		}
665 setup_link:
666 		if (err == 0) {
667 			if (ixgbe_driver_setup_link(ixgbe, B_TRUE) !=
668 			    IXGBE_SUCCESS)
669 				err = EINVAL;
670 		}
671 		break;
672 	case MAC_PROP_ADV_10GFDX_CAP:
673 	case MAC_PROP_ADV_1000FDX_CAP:
674 	case MAC_PROP_ADV_100FDX_CAP:
675 	case MAC_PROP_STATUS:
676 	case MAC_PROP_SPEED:
677 	case MAC_PROP_DUPLEX:
678 		err = ENOTSUP; /* read-only prop. Can't set this. */
679 		break;
680 	case MAC_PROP_MTU:
681 		cur_mtu = ixgbe->default_mtu;
682 		bcopy(pr_val, &new_mtu, sizeof (new_mtu));
683 		if (new_mtu == cur_mtu) {
684 			err = 0;
685 			break;
686 		}
687 
688 		if (new_mtu < DEFAULT_MTU || new_mtu > MAX_MTU) {
689 			err = EINVAL;
690 			break;
691 		}
692 
693 		if (ixgbe->ixgbe_state & IXGBE_STARTED) {
694 			err = EBUSY;
695 			break;
696 		}
697 
698 		err = mac_maxsdu_update(ixgbe->mac_hdl, new_mtu);
699 		if (err == 0) {
700 			ixgbe->default_mtu = new_mtu;
701 			ixgbe->max_frame_size = ixgbe->default_mtu +
702 			    sizeof (struct ether_vlan_header) + ETHERFCSL;
703 
704 			/*
705 			 * Set rx buffer size
706 			 */
707 			rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
708 			ixgbe->rx_buf_size = ((rx_size >> 10) + ((rx_size &
709 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
710 
711 			/*
712 			 * Set tx buffer size
713 			 */
714 			tx_size = ixgbe->max_frame_size;
715 			ixgbe->tx_buf_size = ((tx_size >> 10) + ((tx_size &
716 			    (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
717 		}
718 		break;
719 	case MAC_PROP_PRIVATE:
720 		err = ixgbe_set_priv_prop(ixgbe, pr_name, pr_valsize, pr_val);
721 		break;
722 	default:
723 		err = EINVAL;
724 		break;
725 	}
726 	mutex_exit(&ixgbe->gen_lock);
727 	return (err);
728 }
729 
730 int
731 ixgbe_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
732     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
733 {
734 	ixgbe_t *ixgbe = (ixgbe_t *)arg;
735 	struct ixgbe_hw *hw = &ixgbe->hw;
736 	int err = 0;
737 	uint32_t flow_control;
738 	uint64_t tmp = 0;
739 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
740 	mac_propval_range_t range;
741 
742 	if (pr_valsize == 0)
743 		return (EINVAL);
744 
745 	*perm = MAC_PROP_PERM_READ;
746 
747 	bzero(pr_val, pr_valsize);
748 
749 	switch (pr_num) {
750 	case MAC_PROP_DUPLEX:
751 		if (pr_valsize >= sizeof (link_duplex_t)) {
752 			bcopy(&ixgbe->link_duplex, pr_val,
753 			    sizeof (link_duplex_t));
754 		} else
755 			err = EINVAL;
756 		break;
757 	case MAC_PROP_SPEED:
758 		if (pr_valsize >= sizeof (uint64_t)) {
759 			tmp = ixgbe->link_speed * 1000000ull;
760 			bcopy(&tmp, pr_val, sizeof (tmp));
761 		} else
762 			err = EINVAL;
763 		break;
764 	case MAC_PROP_AUTONEG:
765 		if (ixgbe->hw.phy.media_type == ixgbe_media_type_copper)
766 			*perm = MAC_PROP_PERM_RW;
767 		*(uint8_t *)pr_val =
768 		    (is_default ? 1 : ixgbe->param_adv_autoneg_cap);
769 		break;
770 	case MAC_PROP_FLOWCTRL:
771 		*perm = MAC_PROP_PERM_RW;
772 		if (pr_valsize >= sizeof (uint32_t)) {
773 			if (is_default) {
774 				flow_control = LINK_FLOWCTRL_NONE;
775 				bcopy(&flow_control, pr_val,
776 				    sizeof (flow_control));
777 				break;
778 			}
779 			switch (hw->fc.requested_mode) {
780 				case ixgbe_fc_none:
781 					flow_control = LINK_FLOWCTRL_NONE;
782 					break;
783 				case ixgbe_fc_rx_pause:
784 					flow_control = LINK_FLOWCTRL_RX;
785 					break;
786 				case ixgbe_fc_tx_pause:
787 					flow_control = LINK_FLOWCTRL_TX;
788 					break;
789 				case ixgbe_fc_full:
790 					flow_control = LINK_FLOWCTRL_BI;
791 					break;
792 			}
793 			bcopy(&flow_control, pr_val, sizeof (flow_control));
794 		} else
795 			err = EINVAL;
796 		break;
797 	case MAC_PROP_ADV_10GFDX_CAP:
798 		*(uint8_t *)pr_val = (is_default ? 1 :
799 		    ixgbe->param_adv_10000fdx_cap);
800 		break;
801 	case MAC_PROP_EN_10GFDX_CAP:
802 		if (ixgbe->hw.phy.media_type == ixgbe_media_type_copper)
803 			*perm = MAC_PROP_PERM_RW;
804 		*(uint8_t *)pr_val =
805 		    (is_default ? 1 : ixgbe->param_en_10000fdx_cap);
806 		break;
807 	case MAC_PROP_ADV_1000FDX_CAP:
808 		*(uint8_t *)pr_val = (is_default ? 1 :
809 		    ixgbe->param_adv_1000fdx_cap);
810 		break;
811 	case MAC_PROP_EN_1000FDX_CAP:
812 		if (ixgbe->hw.phy.media_type == ixgbe_media_type_copper)
813 			*perm = MAC_PROP_PERM_RW;
814 		*(uint8_t *)pr_val =
815 		    (is_default ? 1 : ixgbe->param_en_1000fdx_cap);
816 		break;
817 	case MAC_PROP_ADV_100FDX_CAP:
818 		*(uint8_t *)pr_val =
819 		    (is_default ? 1 : ixgbe->param_adv_100fdx_cap);
820 		break;
821 	case MAC_PROP_EN_100FDX_CAP:
822 		if (ixgbe->hw.phy.media_type == ixgbe_media_type_copper)
823 			*perm = MAC_PROP_PERM_RW;
824 		*(uint8_t *)pr_val =
825 		    (is_default ? 1 : ixgbe->param_en_100fdx_cap);
826 		break;
827 	case MAC_PROP_PRIVATE:
828 		err = ixgbe_get_priv_prop(ixgbe, pr_name,
829 		    pr_flags, pr_valsize, pr_val, perm);
830 		break;
831 	case MAC_PROP_MTU:
832 		if (!(pr_flags & MAC_PROP_POSSIBLE))
833 			return (ENOTSUP);
834 		if (pr_valsize < sizeof (mac_propval_range_t))
835 			return (EINVAL);
836 		range.mpr_count = 1;
837 		range.mpr_type = MAC_PROPVAL_UINT32;
838 		range.range_uint32[0].mpur_min = DEFAULT_MTU;
839 		range.range_uint32[0].mpur_max = MAX_MTU;
840 		bcopy(&range, pr_val, sizeof (range));
841 		break;
842 	default:
843 		err = EINVAL;
844 		break;
845 	}
846 	return (err);
847 }
848 
849 boolean_t
850 ixgbe_param_locked(mac_prop_id_t pr_num)
851 {
852 	/*
853 	 * All en_* parameters are locked (read-only) while
854 	 * the device is in any sort of loopback mode ...
855 	 */
856 	switch (pr_num) {
857 		case MAC_PROP_EN_10GFDX_CAP:
858 		case MAC_PROP_EN_1000FDX_CAP:
859 		case MAC_PROP_EN_100FDX_CAP:
860 		case MAC_PROP_AUTONEG:
861 		case MAC_PROP_FLOWCTRL:
862 			return (B_TRUE);
863 	}
864 	return (B_FALSE);
865 }
866 
867 /* ARGSUSED */
868 int
869 ixgbe_set_priv_prop(ixgbe_t *ixgbe, const char *pr_name,
870     uint_t pr_valsize, const void *pr_val)
871 {
872 	int err = 0;
873 	long result;
874 	struct ixgbe_hw *hw = &ixgbe->hw;
875 	int i;
876 
877 	if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
878 		if (pr_val == NULL) {
879 			err = EINVAL;
880 			return (err);
881 		}
882 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
883 		if (result < MIN_TX_COPY_THRESHOLD ||
884 		    result > MAX_TX_COPY_THRESHOLD)
885 			err = EINVAL;
886 		else {
887 			ixgbe->tx_copy_thresh = (uint32_t)result;
888 		}
889 		return (err);
890 	}
891 	if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
892 		if (pr_val == NULL) {
893 			err = EINVAL;
894 			return (err);
895 		}
896 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
897 		if (result < MIN_TX_RECYCLE_THRESHOLD ||
898 		    result > MAX_TX_RECYCLE_THRESHOLD)
899 			err = EINVAL;
900 		else {
901 			ixgbe->tx_recycle_thresh = (uint32_t)result;
902 		}
903 		return (err);
904 	}
905 	if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
906 		if (pr_val == NULL) {
907 			err = EINVAL;
908 			return (err);
909 		}
910 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
911 		if (result < MIN_TX_OVERLOAD_THRESHOLD ||
912 		    result > MAX_TX_OVERLOAD_THRESHOLD)
913 			err = EINVAL;
914 		else {
915 			ixgbe->tx_overload_thresh = (uint32_t)result;
916 		}
917 		return (err);
918 	}
919 	if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
920 		if (pr_val == NULL) {
921 			err = EINVAL;
922 			return (err);
923 		}
924 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
925 		if (result < MIN_TX_RESCHED_THRESHOLD ||
926 		    result > MAX_TX_RESCHED_THRESHOLD)
927 			err = EINVAL;
928 		else {
929 			ixgbe->tx_resched_thresh = (uint32_t)result;
930 		}
931 		return (err);
932 	}
933 	if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
934 		if (pr_val == NULL) {
935 			err = EINVAL;
936 			return (err);
937 		}
938 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
939 		if (result < MIN_RX_COPY_THRESHOLD ||
940 		    result > MAX_RX_COPY_THRESHOLD)
941 			err = EINVAL;
942 		else {
943 			ixgbe->rx_copy_thresh = (uint32_t)result;
944 		}
945 		return (err);
946 	}
947 	if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
948 		if (pr_val == NULL) {
949 			err = EINVAL;
950 			return (err);
951 		}
952 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
953 		if (result < MIN_RX_LIMIT_PER_INTR ||
954 		    result > MAX_RX_LIMIT_PER_INTR)
955 			err = EINVAL;
956 		else {
957 			ixgbe->rx_limit_per_intr = (uint32_t)result;
958 		}
959 		return (err);
960 	}
961 	if (strcmp(pr_name, "_intr_throttling") == 0) {
962 		if (pr_val == NULL) {
963 			err = EINVAL;
964 			return (err);
965 		}
966 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
967 
968 		if (result < ixgbe->capab->min_intr_throttle ||
969 		    result > ixgbe->capab->max_intr_throttle)
970 			err = EINVAL;
971 		else {
972 			ixgbe->intr_throttling[0] = (uint32_t)result;
973 
974 			/*
975 			 * 82599 requires the interupt throttling rate is
976 			 * a multiple of 8. This is enforced by the register
977 			 * definiton.
978 			 */
979 			if (hw->mac.type == ixgbe_mac_82599EB)
980 				ixgbe->intr_throttling[0] =
981 				    ixgbe->intr_throttling[0] & 0xFF8;
982 
983 			for (i = 0; i < MAX_INTR_VECTOR; i++)
984 				ixgbe->intr_throttling[i] =
985 				    ixgbe->intr_throttling[0];
986 
987 			/* Set interrupt throttling rate */
988 			for (i = 0; i < ixgbe->intr_cnt; i++)
989 				IXGBE_WRITE_REG(hw, IXGBE_EITR(i),
990 				    ixgbe->intr_throttling[i]);
991 		}
992 		return (err);
993 	}
994 	return (ENOTSUP);
995 }
996 
997 int
998 ixgbe_get_priv_prop(ixgbe_t *ixgbe, const char *pr_name,
999     uint_t pr_flags, uint_t pr_valsize, void *pr_val, uint_t *perm)
1000 {
1001 	int err = ENOTSUP;
1002 	boolean_t is_default = (pr_flags & MAC_PROP_DEFAULT);
1003 	int value;
1004 
1005 	*perm = MAC_PROP_PERM_RW;
1006 
1007 	if (strcmp(pr_name, "_adv_pause_cap") == 0) {
1008 		*perm = MAC_PROP_PERM_READ;
1009 		value = (is_default ? 1 : ixgbe->param_adv_pause_cap);
1010 		err = 0;
1011 		goto done;
1012 	}
1013 	if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
1014 		*perm = MAC_PROP_PERM_READ;
1015 		value = (is_default ? 1 : ixgbe->param_adv_asym_pause_cap);
1016 		err = 0;
1017 		goto done;
1018 	}
1019 	if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
1020 		value = (is_default ? DEFAULT_TX_COPY_THRESHOLD :
1021 		    ixgbe->tx_copy_thresh);
1022 		err = 0;
1023 		goto done;
1024 	}
1025 	if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
1026 		value = (is_default ? DEFAULT_TX_RECYCLE_THRESHOLD :
1027 		    ixgbe->tx_recycle_thresh);
1028 		err = 0;
1029 		goto done;
1030 	}
1031 	if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
1032 		value = (is_default ? DEFAULT_TX_OVERLOAD_THRESHOLD :
1033 		    ixgbe->tx_overload_thresh);
1034 		err = 0;
1035 		goto done;
1036 	}
1037 	if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
1038 		value = (is_default ? DEFAULT_TX_RESCHED_THRESHOLD :
1039 		    ixgbe->tx_resched_thresh);
1040 		err = 0;
1041 		goto done;
1042 	}
1043 	if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
1044 		value = (is_default ? DEFAULT_RX_COPY_THRESHOLD :
1045 		    ixgbe->rx_copy_thresh);
1046 		err = 0;
1047 		goto done;
1048 	}
1049 	if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
1050 		value = (is_default ? DEFAULT_RX_LIMIT_PER_INTR :
1051 		    ixgbe->rx_limit_per_intr);
1052 		err = 0;
1053 		goto done;
1054 	}
1055 	if (strcmp(pr_name, "_intr_throttling") == 0) {
1056 		value = (is_default ? ixgbe->capab->def_intr_throttle :
1057 		    ixgbe->intr_throttling[0]);
1058 		err = 0;
1059 		goto done;
1060 	}
1061 done:
1062 	if (err == 0) {
1063 		(void) snprintf(pr_val, pr_valsize, "%d", value);
1064 	}
1065 	return (err);
1066 }
1067