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