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