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 */
31
32 #include "ixgbe_sw.h"
33
34 /*
35 * Bring the device out of the reset/quiesced state that it
36 * was in when the interface was registered.
37 */
38 int
39 ixgbe_m_start(void *arg)
40 {
41 ixgbe_t *ixgbe = (ixgbe_t *)arg;
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 if (ixgbe_start(ixgbe, B_TRUE) != IXGBE_SUCCESS) {
51 mutex_exit(&ixgbe->gen_lock);
52 return (EIO);
53 }
54
55 atomic_or_32(&ixgbe->ixgbe_state, IXGBE_STARTED);
56
57 mutex_exit(&ixgbe->gen_lock);
58
59 /*
60 * Enable and start the watchdog timer
61 */
62 ixgbe_enable_watchdog_timer(ixgbe);
63
64 return (0);
65 }
66
67 /*
68 * Stop the device and put it in a reset/quiesced state such
69 * that the interface can be unregistered.
70 */
71 void
72 ixgbe_m_stop(void *arg)
73 {
74 ixgbe_t *ixgbe = (ixgbe_t *)arg;
75
76 mutex_enter(&ixgbe->gen_lock);
77
78 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
79 mutex_exit(&ixgbe->gen_lock);
80 return;
81 }
82
83 atomic_and_32(&ixgbe->ixgbe_state, ~IXGBE_STARTED);
84
85 ixgbe_stop(ixgbe, B_TRUE);
86
87 mutex_exit(&ixgbe->gen_lock);
88
89 /*
90 * Disable and stop the watchdog timer
91 */
92 ixgbe_disable_watchdog_timer(ixgbe);
93 }
94
95 /*
96 * Set the promiscuity of the device.
97 */
98 int
99 ixgbe_m_promisc(void *arg, boolean_t on)
100 {
101 ixgbe_t *ixgbe = (ixgbe_t *)arg;
102 uint32_t reg_val;
103 struct ixgbe_hw *hw = &ixgbe->hw;
104
105 mutex_enter(&ixgbe->gen_lock);
106
107 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
108 mutex_exit(&ixgbe->gen_lock);
109 return (ECANCELED);
110 }
111 reg_val = IXGBE_READ_REG(hw, IXGBE_FCTRL);
112
113 if (on)
114 reg_val |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
115 else
116 reg_val &= (~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE));
117
118 IXGBE_WRITE_REG(&ixgbe->hw, IXGBE_FCTRL, reg_val);
119
120 mutex_exit(&ixgbe->gen_lock);
121
122 return (0);
123 }
124
125 /*
126 * Add/remove the addresses to/from the set of multicast
127 * addresses for which the device will receive packets.
128 */
129 int
130 ixgbe_m_multicst(void *arg, boolean_t add, const uint8_t *mcst_addr)
131 {
132 ixgbe_t *ixgbe = (ixgbe_t *)arg;
133 int result;
134
135 mutex_enter(&ixgbe->gen_lock);
136
137 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
138 mutex_exit(&ixgbe->gen_lock);
139 return (ECANCELED);
140 }
141
142 result = (add) ? ixgbe_multicst_add(ixgbe, mcst_addr)
143 : ixgbe_multicst_remove(ixgbe, mcst_addr);
144
145 mutex_exit(&ixgbe->gen_lock);
146
147 return (result);
148 }
149
150 /*
151 * Pass on M_IOCTL messages passed to the DLD, and support
152 * private IOCTLs for debugging and ndd.
153 */
154 void
155 ixgbe_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
156 {
157 ixgbe_t *ixgbe = (ixgbe_t *)arg;
158 struct iocblk *iocp;
159 enum ioc_reply status;
160
161 iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
162 iocp->ioc_error = 0;
163
164 mutex_enter(&ixgbe->gen_lock);
165 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
166 mutex_exit(&ixgbe->gen_lock);
167 miocnak(q, mp, 0, EINVAL);
168 return;
169 }
170 mutex_exit(&ixgbe->gen_lock);
171
172 switch (iocp->ioc_cmd) {
173 case LB_GET_INFO_SIZE:
174 case LB_GET_INFO:
175 case LB_GET_MODE:
176 case LB_SET_MODE:
177 status = ixgbe_loopback_ioctl(ixgbe, iocp, mp);
178 break;
179
180 default:
181 status = IOC_INVAL;
182 break;
183 }
184
185 /*
186 * Decide how to reply
187 */
188 switch (status) {
189 default:
190 case IOC_INVAL:
191 /*
192 * Error, reply with a NAK and EINVAL or the specified error
193 */
194 miocnak(q, mp, 0, iocp->ioc_error == 0 ?
195 EINVAL : iocp->ioc_error);
196 break;
197
198 case IOC_DONE:
199 /*
200 * OK, reply already sent
201 */
202 break;
203
204 case IOC_ACK:
205 /*
206 * OK, reply with an ACK
207 */
208 miocack(q, mp, 0, 0);
209 break;
210
211 case IOC_REPLY:
212 /*
213 * OK, send prepared reply as ACK or NAK
214 */
215 mp->b_datap->db_type = iocp->ioc_error == 0 ?
216 M_IOCACK : M_IOCNAK;
217 qreply(q, mp);
218 break;
219 }
220 }
221
222 /*
223 * Obtain the MAC's capabilities and associated data from
224 * the driver.
225 */
226 boolean_t
227 ixgbe_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
228 {
229 ixgbe_t *ixgbe = (ixgbe_t *)arg;
230
231 switch (cap) {
232 case MAC_CAPAB_HCKSUM: {
233 uint32_t *tx_hcksum_flags = cap_data;
234
235 /*
236 * We advertise our capabilities only if tx hcksum offload is
237 * enabled. On receive, the stack will accept checksummed
238 * packets anyway, even if we haven't said we can deliver
239 * them.
240 */
241 if (!ixgbe->tx_hcksum_enable)
242 return (B_FALSE);
243
244 *tx_hcksum_flags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
245 break;
246 }
247 case MAC_CAPAB_LSO: {
248 mac_capab_lso_t *cap_lso = cap_data;
249
250 if (ixgbe->lso_enable) {
251 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
252 cap_lso->lso_basic_tcp_ipv4.lso_max = IXGBE_LSO_MAXLEN;
253 break;
254 } else {
255 return (B_FALSE);
256 }
257 }
258 case MAC_CAPAB_RINGS: {
259 mac_capab_rings_t *cap_rings = cap_data;
260
261 switch (cap_rings->mr_type) {
262 case MAC_RING_TYPE_RX:
263 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
264 cap_rings->mr_rnum = ixgbe->num_rx_rings;
265 cap_rings->mr_gnum = ixgbe->num_rx_groups;
266 cap_rings->mr_rget = ixgbe_fill_ring;
267 cap_rings->mr_gget = ixgbe_fill_group;
268 cap_rings->mr_gaddring = NULL;
269 cap_rings->mr_gremring = NULL;
270 break;
271 case MAC_RING_TYPE_TX:
272 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
273 cap_rings->mr_rnum = ixgbe->num_tx_rings;
274 cap_rings->mr_gnum = 0;
275 cap_rings->mr_rget = ixgbe_fill_ring;
276 cap_rings->mr_gget = NULL;
277 break;
278 default:
279 break;
280 }
281 break;
282 }
283 default:
284 return (B_FALSE);
285 }
286 return (B_TRUE);
287 }
288
289 int
290 ixgbe_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
291 uint_t pr_valsize, const void *pr_val)
292 {
293 ixgbe_t *ixgbe = (ixgbe_t *)arg;
294 struct ixgbe_hw *hw = &ixgbe->hw;
295 int err = 0;
296 uint32_t flow_control;
297 uint32_t cur_mtu, new_mtu;
298 uint32_t rx_size;
299 uint32_t tx_size;
300
301 mutex_enter(&ixgbe->gen_lock);
302 if (ixgbe->ixgbe_state & IXGBE_SUSPENDED) {
303 mutex_exit(&ixgbe->gen_lock);
304 return (ECANCELED);
305 }
306
307 if (ixgbe->loopback_mode != IXGBE_LB_NONE &&
308 ixgbe_param_locked(pr_num)) {
309 /*
310 * All en_* parameters are locked (read-only)
311 * while the device is in any sort of loopback mode.
312 */
313 mutex_exit(&ixgbe->gen_lock);
314 return (EBUSY);
315 }
316
317 switch (pr_num) {
318 case MAC_PROP_EN_10GFDX_CAP:
319 /* read/write on copper, read-only on serdes */
320 if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
321 err = ENOTSUP;
322 break;
323 } else {
324 ixgbe->param_en_10000fdx_cap = *(uint8_t *)pr_val;
325 ixgbe->param_adv_10000fdx_cap = *(uint8_t *)pr_val;
326 goto setup_link;
327 }
328 case MAC_PROP_EN_1000FDX_CAP:
329 /* read/write on copper, read-only on serdes */
330 if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
331 err = ENOTSUP;
332 break;
333 } else {
334 ixgbe->param_en_1000fdx_cap = *(uint8_t *)pr_val;
335 ixgbe->param_adv_1000fdx_cap = *(uint8_t *)pr_val;
336 goto setup_link;
337 }
338 case MAC_PROP_EN_100FDX_CAP:
339 /* read/write on copper, read-only on serdes */
340 if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
341 err = ENOTSUP;
342 break;
343 } else {
344 ixgbe->param_en_100fdx_cap = *(uint8_t *)pr_val;
345 ixgbe->param_adv_100fdx_cap = *(uint8_t *)pr_val;
346 goto setup_link;
347 }
348 case MAC_PROP_AUTONEG:
349 /* read/write on copper, read-only on serdes */
350 if (ixgbe->hw.phy.media_type != ixgbe_media_type_copper) {
351 err = ENOTSUP;
352 break;
353 } else {
354 ixgbe->param_adv_autoneg_cap = *(uint8_t *)pr_val;
355 goto setup_link;
356 }
357 case MAC_PROP_FLOWCTRL:
358 bcopy(pr_val, &flow_control, sizeof (flow_control));
359
360 switch (flow_control) {
361 default:
362 err = EINVAL;
363 break;
364 case LINK_FLOWCTRL_NONE:
365 hw->fc.requested_mode = ixgbe_fc_none;
366 break;
367 case LINK_FLOWCTRL_RX:
368 hw->fc.requested_mode = ixgbe_fc_rx_pause;
369 break;
370 case LINK_FLOWCTRL_TX:
371 hw->fc.requested_mode = ixgbe_fc_tx_pause;
372 break;
373 case LINK_FLOWCTRL_BI:
374 hw->fc.requested_mode = ixgbe_fc_full;
375 break;
376 }
377 setup_link:
378 if (err == 0) {
379 if (ixgbe_driver_setup_link(ixgbe, B_TRUE) !=
380 IXGBE_SUCCESS)
381 err = EINVAL;
382 }
383 break;
384 case MAC_PROP_ADV_10GFDX_CAP:
385 case MAC_PROP_ADV_1000FDX_CAP:
386 case MAC_PROP_ADV_100FDX_CAP:
387 case MAC_PROP_STATUS:
388 case MAC_PROP_SPEED:
389 case MAC_PROP_DUPLEX:
390 err = ENOTSUP; /* read-only prop. Can't set this. */
391 break;
392 case MAC_PROP_MTU:
393 cur_mtu = ixgbe->default_mtu;
394 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
395 if (new_mtu == cur_mtu) {
396 err = 0;
397 break;
398 }
399
400 if (new_mtu < DEFAULT_MTU || new_mtu > ixgbe->capab->max_mtu) {
401 err = EINVAL;
402 break;
403 }
404
405 if (ixgbe->ixgbe_state & IXGBE_STARTED) {
406 err = EBUSY;
407 break;
408 }
409
410 err = mac_maxsdu_update(ixgbe->mac_hdl, new_mtu);
411 if (err == 0) {
412 ixgbe->default_mtu = new_mtu;
413 ixgbe->max_frame_size = ixgbe->default_mtu +
414 sizeof (struct ether_vlan_header) + ETHERFCSL;
415
416 /*
417 * Set rx buffer size
418 */
419 rx_size = ixgbe->max_frame_size + IPHDR_ALIGN_ROOM;
420 ixgbe->rx_buf_size = ((rx_size >> 10) + ((rx_size &
421 (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
422
423 /*
424 * Set tx buffer size
425 */
426 tx_size = ixgbe->max_frame_size;
427 ixgbe->tx_buf_size = ((tx_size >> 10) + ((tx_size &
428 (((uint32_t)1 << 10) - 1)) > 0 ? 1 : 0)) << 10;
429 }
430 break;
431 case MAC_PROP_PRIVATE:
432 err = ixgbe_set_priv_prop(ixgbe, pr_name, pr_valsize, pr_val);
433 break;
434 default:
435 err = ENOTSUP;
436 break;
437 }
438 mutex_exit(&ixgbe->gen_lock);
439 return (err);
440 }
441
442 int
443 ixgbe_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
444 uint_t pr_valsize, void *pr_val)
445 {
446 ixgbe_t *ixgbe = (ixgbe_t *)arg;
447 struct ixgbe_hw *hw = &ixgbe->hw;
448 int err = 0;
449 uint32_t flow_control;
450 uint64_t tmp = 0;
451
452 switch (pr_num) {
453 case MAC_PROP_DUPLEX:
454 ASSERT(pr_valsize >= sizeof (link_duplex_t));
455 bcopy(&ixgbe->link_duplex, pr_val,
456 sizeof (link_duplex_t));
457 break;
458 case MAC_PROP_SPEED:
459 ASSERT(pr_valsize >= sizeof (uint64_t));
460 tmp = ixgbe->link_speed * 1000000ull;
461 bcopy(&tmp, pr_val, sizeof (tmp));
462 break;
463 case MAC_PROP_AUTONEG:
464 *(uint8_t *)pr_val = ixgbe->param_adv_autoneg_cap;
465 break;
466 case MAC_PROP_FLOWCTRL:
467 ASSERT(pr_valsize >= sizeof (uint32_t));
468
469 switch (hw->fc.requested_mode) {
470 case ixgbe_fc_none:
471 flow_control = LINK_FLOWCTRL_NONE;
472 break;
473 case ixgbe_fc_rx_pause:
474 flow_control = LINK_FLOWCTRL_RX;
475 break;
476 case ixgbe_fc_tx_pause:
477 flow_control = LINK_FLOWCTRL_TX;
478 break;
479 case ixgbe_fc_full:
480 flow_control = LINK_FLOWCTRL_BI;
481 break;
482 }
483 bcopy(&flow_control, pr_val, sizeof (flow_control));
484 break;
485 case MAC_PROP_ADV_10GFDX_CAP:
486 *(uint8_t *)pr_val = ixgbe->param_adv_10000fdx_cap;
487 break;
488 case MAC_PROP_EN_10GFDX_CAP:
489 *(uint8_t *)pr_val = ixgbe->param_en_10000fdx_cap;
490 break;
491 case MAC_PROP_ADV_1000FDX_CAP:
492 *(uint8_t *)pr_val = ixgbe->param_adv_1000fdx_cap;
493 break;
494 case MAC_PROP_EN_1000FDX_CAP:
495 *(uint8_t *)pr_val = ixgbe->param_en_1000fdx_cap;
496 break;
497 case MAC_PROP_ADV_100FDX_CAP:
498 *(uint8_t *)pr_val = ixgbe->param_adv_100fdx_cap;
499 break;
500 case MAC_PROP_EN_100FDX_CAP:
501 *(uint8_t *)pr_val = ixgbe->param_en_100fdx_cap;
502 break;
503 case MAC_PROP_PRIVATE:
504 err = ixgbe_get_priv_prop(ixgbe, pr_name,
505 pr_valsize, pr_val);
506 break;
507 default:
508 err = ENOTSUP;
509 break;
510 }
511 return (err);
512 }
513
514 void
515 ixgbe_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
516 mac_prop_info_handle_t prh)
517 {
518 ixgbe_t *ixgbe = (ixgbe_t *)arg;
519 uint_t perm;
520
521 switch (pr_num) {
522 case MAC_PROP_DUPLEX:
523 case MAC_PROP_SPEED:
524 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
525 break;
526
527 case MAC_PROP_ADV_100FDX_CAP:
528 case MAC_PROP_ADV_1000FDX_CAP:
529 case MAC_PROP_ADV_10GFDX_CAP:
530 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
531 mac_prop_info_set_default_uint8(prh, 1);
532 break;
533
534 case MAC_PROP_AUTONEG:
535 case MAC_PROP_EN_10GFDX_CAP:
536 case MAC_PROP_EN_1000FDX_CAP:
537 case MAC_PROP_EN_100FDX_CAP:
538 perm = (ixgbe->hw.phy.media_type == ixgbe_media_type_copper) ?
539 MAC_PROP_PERM_RW : MAC_PROP_PERM_READ;
540 mac_prop_info_set_perm(prh, perm);
541 mac_prop_info_set_default_uint8(prh, 1);
542 break;
543
544 case MAC_PROP_FLOWCTRL:
545 mac_prop_info_set_default_link_flowctrl(prh,
546 LINK_FLOWCTRL_NONE);
547 break;
548
549 case MAC_PROP_MTU:
550 mac_prop_info_set_range_uint32(prh,
551 DEFAULT_MTU, ixgbe->capab->max_mtu);
552 break;
553
554 case MAC_PROP_PRIVATE: {
555 char valstr[64];
556 int value;
557
558 bzero(valstr, sizeof (valstr));
559
560 if (strcmp(pr_name, "_adv_pause_cap") == 0 ||
561 strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
562 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
563 return;
564 }
565
566 if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
567 value = DEFAULT_TX_COPY_THRESHOLD;
568 } else if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
569 value = DEFAULT_TX_RECYCLE_THRESHOLD;
570 } else if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
571 value = DEFAULT_TX_OVERLOAD_THRESHOLD;
572 } else if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
573 value = DEFAULT_TX_RESCHED_THRESHOLD;
574 } else if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
575 value = DEFAULT_RX_COPY_THRESHOLD;
576 } else if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
577 value = DEFAULT_RX_LIMIT_PER_INTR;
578 } if (strcmp(pr_name, "_intr_throttling") == 0) {
579 value = ixgbe->capab->def_intr_throttle;
580 } else {
581 return;
582 }
583
584 (void) snprintf(valstr, sizeof (valstr), "%x", value);
585 }
586 }
587 }
588
589 boolean_t
590 ixgbe_param_locked(mac_prop_id_t pr_num)
591 {
592 /*
593 * All en_* parameters are locked (read-only) while
594 * the device is in any sort of loopback mode ...
595 */
596 switch (pr_num) {
597 case MAC_PROP_EN_10GFDX_CAP:
598 case MAC_PROP_EN_1000FDX_CAP:
599 case MAC_PROP_EN_100FDX_CAP:
600 case MAC_PROP_AUTONEG:
601 case MAC_PROP_FLOWCTRL:
602 return (B_TRUE);
603 }
604 return (B_FALSE);
605 }
606
607 /* ARGSUSED */
608 int
609 ixgbe_set_priv_prop(ixgbe_t *ixgbe, const char *pr_name,
610 uint_t pr_valsize, const void *pr_val)
611 {
612 int err = 0;
613 long result;
614 struct ixgbe_hw *hw = &ixgbe->hw;
615 int i;
616
617 if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
618 if (pr_val == NULL) {
619 err = EINVAL;
620 return (err);
621 }
622 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
623 if (result < MIN_TX_COPY_THRESHOLD ||
624 result > MAX_TX_COPY_THRESHOLD)
625 err = EINVAL;
626 else {
627 ixgbe->tx_copy_thresh = (uint32_t)result;
628 }
629 return (err);
630 }
631 if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
632 if (pr_val == NULL) {
633 err = EINVAL;
634 return (err);
635 }
636 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
637 if (result < MIN_TX_RECYCLE_THRESHOLD ||
638 result > MAX_TX_RECYCLE_THRESHOLD)
639 err = EINVAL;
640 else {
641 ixgbe->tx_recycle_thresh = (uint32_t)result;
642 }
643 return (err);
644 }
645 if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
646 if (pr_val == NULL) {
647 err = EINVAL;
648 return (err);
649 }
650 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
651 if (result < MIN_TX_OVERLOAD_THRESHOLD ||
652 result > MAX_TX_OVERLOAD_THRESHOLD)
653 err = EINVAL;
654 else {
655 ixgbe->tx_overload_thresh = (uint32_t)result;
656 }
657 return (err);
658 }
659 if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
660 if (pr_val == NULL) {
661 err = EINVAL;
662 return (err);
663 }
664 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
665 if (result < MIN_TX_RESCHED_THRESHOLD ||
666 result > MAX_TX_RESCHED_THRESHOLD)
667 err = EINVAL;
668 else {
669 ixgbe->tx_resched_thresh = (uint32_t)result;
670 }
671 return (err);
672 }
673 if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
674 if (pr_val == NULL) {
675 err = EINVAL;
676 return (err);
677 }
678 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
679 if (result < MIN_RX_COPY_THRESHOLD ||
680 result > MAX_RX_COPY_THRESHOLD)
681 err = EINVAL;
682 else {
683 ixgbe->rx_copy_thresh = (uint32_t)result;
684 }
685 return (err);
686 }
687 if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
688 if (pr_val == NULL) {
689 err = EINVAL;
690 return (err);
691 }
692 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
693 if (result < MIN_RX_LIMIT_PER_INTR ||
694 result > MAX_RX_LIMIT_PER_INTR)
695 err = EINVAL;
696 else {
697 ixgbe->rx_limit_per_intr = (uint32_t)result;
698 }
699 return (err);
700 }
701 if (strcmp(pr_name, "_intr_throttling") == 0) {
702 if (pr_val == NULL) {
703 err = EINVAL;
704 return (err);
705 }
706 (void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
707
708 if (result < ixgbe->capab->min_intr_throttle ||
709 result > ixgbe->capab->max_intr_throttle)
710 err = EINVAL;
711 else {
712 ixgbe->intr_throttling[0] = (uint32_t)result;
713
714 /*
715 * 82599 and X540 require the interrupt throttling
716 * rate is a multiple of 8. This is enforced by the
717 * register definiton.
718 */
719 if (hw->mac.type == ixgbe_mac_82599EB ||
720 hw->mac.type == ixgbe_mac_X540) {
721 ixgbe->intr_throttling[0] =
722 ixgbe->intr_throttling[0] & 0xFF8;
723 }
724
725 for (i = 0; i < MAX_INTR_VECTOR; i++)
726 ixgbe->intr_throttling[i] =
727 ixgbe->intr_throttling[0];
728
729 /* Set interrupt throttling rate */
730 for (i = 0; i < ixgbe->intr_cnt; i++)
731 IXGBE_WRITE_REG(hw, IXGBE_EITR(i),
732 ixgbe->intr_throttling[i]);
733 }
734 return (err);
735 }
736 return (ENOTSUP);
737 }
738
739 int
740 ixgbe_get_priv_prop(ixgbe_t *ixgbe, const char *pr_name,
741 uint_t pr_valsize, void *pr_val)
742 {
743 int err = ENOTSUP;
744 int value;
745
746 if (strcmp(pr_name, "_adv_pause_cap") == 0) {
747 value = ixgbe->param_adv_pause_cap;
748 err = 0;
749 goto done;
750 }
751 if (strcmp(pr_name, "_adv_asym_pause_cap") == 0) {
752 value = ixgbe->param_adv_asym_pause_cap;
753 err = 0;
754 goto done;
755 }
756 if (strcmp(pr_name, "_tx_copy_thresh") == 0) {
757 value = ixgbe->tx_copy_thresh;
758 err = 0;
759 goto done;
760 }
761 if (strcmp(pr_name, "_tx_recycle_thresh") == 0) {
762 value = ixgbe->tx_recycle_thresh;
763 err = 0;
764 goto done;
765 }
766 if (strcmp(pr_name, "_tx_overload_thresh") == 0) {
767 value = ixgbe->tx_overload_thresh;
768 err = 0;
769 goto done;
770 }
771 if (strcmp(pr_name, "_tx_resched_thresh") == 0) {
772 value = ixgbe->tx_resched_thresh;
773 err = 0;
774 goto done;
775 }
776 if (strcmp(pr_name, "_rx_copy_thresh") == 0) {
777 value = ixgbe->rx_copy_thresh;
778 err = 0;
779 goto done;
780 }
781 if (strcmp(pr_name, "_rx_limit_per_intr") == 0) {
782 value = ixgbe->rx_limit_per_intr;
783 err = 0;
784 goto done;
785 }
786 if (strcmp(pr_name, "_intr_throttling") == 0) {
787 value = ixgbe->intr_throttling[0];
788 err = 0;
789 goto done;
790 }
791 done:
792 if (err == 0) {
793 (void) snprintf(pr_val, pr_valsize, "%d", value);
794 }
795 return (err);
796 }