7790 Want support for XXV710
[unleashed.git] / usr / src / uts / common / io / i40e / i40e_gld.c
blob76c96cf358140238c25863407773901e59b08e63
1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
14 * Copyright 2016 Joyent, Inc.
15 * Copyright 2017 Tegile Systems, Inc. All rights reserved.
19 * For more information, please see the big theory statement in i40e_main.c.
22 #include "i40e_sw.h"
24 #define I40E_PROP_RX_DMA_THRESH "_rx_dma_threshold"
25 #define I40E_PROP_TX_DMA_THRESH "_tx_dma_threshold"
26 #define I40E_PROP_RX_ITR "_rx_intr_throttle"
27 #define I40E_PROP_TX_ITR "_tx_intr_throttle"
28 #define I40E_PROP_OTHER_ITR "_other_intr_throttle"
30 char *i40e_priv_props[] = {
31 I40E_PROP_RX_DMA_THRESH,
32 I40E_PROP_TX_DMA_THRESH,
33 I40E_PROP_RX_ITR,
34 I40E_PROP_TX_ITR,
35 I40E_PROP_OTHER_ITR,
36 NULL
39 static int
40 i40e_group_remove_mac(void *arg, const uint8_t *mac_addr)
42 i40e_t *i40e = arg;
43 struct i40e_aqc_remove_macvlan_element_data filt;
44 struct i40e_hw *hw = &i40e->i40e_hw_space;
45 int ret, i, last;
46 i40e_uaddr_t *iua;
48 if (I40E_IS_MULTICAST(mac_addr))
49 return (EINVAL);
51 mutex_enter(&i40e->i40e_general_lock);
53 if (i40e->i40e_state & I40E_SUSPENDED) {
54 ret = ECANCELED;
55 goto done;
58 for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) {
59 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac,
60 ETHERADDRL) == 0)
61 break;
64 if (i == i40e->i40e_resources.ifr_nmacfilt_used) {
65 ret = ENOENT;
66 goto done;
69 iua = &i40e->i40e_uaddrs[i];
70 ASSERT(i40e->i40e_resources.ifr_nmacfilt_used > 0);
72 bzero(&filt, sizeof (filt));
73 bcopy(mac_addr, filt.mac_addr, ETHERADDRL);
74 filt.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
75 I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
77 if (i40e_aq_remove_macvlan(hw, iua->iua_vsi, &filt, 1, NULL) !=
78 I40E_SUCCESS) {
79 i40e_error(i40e, "failed to remove mac address "
80 "%2x:%2x:%2x:%2x:%2x:%2x from unicast filter: %d",
81 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
82 mac_addr[4], mac_addr[5], filt.error_code);
83 ret = EIO;
84 goto done;
87 last = i40e->i40e_resources.ifr_nmacfilt_used - 1;
88 if (i != last) {
89 i40e_uaddr_t *src = &i40e->i40e_uaddrs[last];
90 bcopy(src, iua, sizeof (i40e_uaddr_t));
94 * Set the multicast bit in the last one to indicate to ourselves that
95 * it's invalid.
97 bzero(&i40e->i40e_uaddrs[last], sizeof (i40e_uaddr_t));
98 i40e->i40e_uaddrs[last].iua_mac[0] = 0x01;
99 i40e->i40e_resources.ifr_nmacfilt_used--;
100 ret = 0;
101 done:
102 mutex_exit(&i40e->i40e_general_lock);
104 return (ret);
107 static int
108 i40e_group_add_mac(void *arg, const uint8_t *mac_addr)
110 i40e_t *i40e = arg;
111 struct i40e_hw *hw = &i40e->i40e_hw_space;
112 int i, ret;
113 i40e_uaddr_t *iua;
114 struct i40e_aqc_add_macvlan_element_data filt;
116 if (I40E_IS_MULTICAST(mac_addr))
117 return (EINVAL);
119 mutex_enter(&i40e->i40e_general_lock);
120 if (i40e->i40e_state & I40E_SUSPENDED) {
121 ret = ECANCELED;
122 goto done;
125 if (i40e->i40e_resources.ifr_nmacfilt ==
126 i40e->i40e_resources.ifr_nmacfilt_used) {
127 ret = ENOSPC;
128 goto done;
131 for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) {
132 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac,
133 ETHERADDRL) == 0) {
134 ret = EEXIST;
135 goto done;
140 * Note, the general use of the i40e_vsi_id will have to be refactored
141 * when we have proper group support.
143 bzero(&filt, sizeof (filt));
144 bcopy(mac_addr, filt.mac_addr, ETHERADDRL);
145 filt.flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH |
146 I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
148 if ((ret = i40e_aq_add_macvlan(hw, i40e->i40e_vsi_id, &filt, 1,
149 NULL)) != I40E_SUCCESS) {
150 i40e_error(i40e, "failed to add mac address "
151 "%2x:%2x:%2x:%2x:%2x:%2x to unicast filter: %d",
152 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
153 mac_addr[4], mac_addr[5], ret);
154 ret = EIO;
155 goto done;
158 iua = &i40e->i40e_uaddrs[i40e->i40e_resources.ifr_nmacfilt_used];
159 bcopy(mac_addr, iua->iua_mac, ETHERADDRL);
160 iua->iua_vsi = i40e->i40e_vsi_id;
161 i40e->i40e_resources.ifr_nmacfilt_used++;
162 ASSERT(i40e->i40e_resources.ifr_nmacfilt_used <=
163 i40e->i40e_resources.ifr_nmacfilt);
164 ret = 0;
165 done:
166 mutex_exit(&i40e->i40e_general_lock);
167 return (ret);
170 static int
171 i40e_m_start(void *arg)
173 i40e_t *i40e = arg;
174 int rc = 0;
176 mutex_enter(&i40e->i40e_general_lock);
177 if (i40e->i40e_state & I40E_SUSPENDED) {
178 rc = ECANCELED;
179 goto done;
182 if (!i40e_start(i40e, B_TRUE)) {
183 rc = EIO;
184 goto done;
187 atomic_or_32(&i40e->i40e_state, I40E_STARTED);
188 done:
189 mutex_exit(&i40e->i40e_general_lock);
191 return (rc);
194 static void
195 i40e_m_stop(void *arg)
197 i40e_t *i40e = arg;
199 mutex_enter(&i40e->i40e_general_lock);
201 if (i40e->i40e_state & I40E_SUSPENDED)
202 goto done;
204 atomic_and_32(&i40e->i40e_state, ~I40E_STARTED);
205 i40e_stop(i40e, B_TRUE);
206 done:
207 mutex_exit(&i40e->i40e_general_lock);
211 * Enable and disable promiscuous mode as requested. We have to toggle both
212 * unicast and multicast. Note that multicast may already be enabled due to the
213 * i40e_m_multicast may toggle it itself. See i40e_main.c for more information
214 * on this.
216 static int
217 i40e_m_promisc(void *arg, boolean_t on)
219 i40e_t *i40e = arg;
220 struct i40e_hw *hw = &i40e->i40e_hw_space;
221 int ret = 0, err = 0;
223 mutex_enter(&i40e->i40e_general_lock);
224 if (i40e->i40e_state & I40E_SUSPENDED) {
225 ret = ECANCELED;
226 goto done;
230 ret = i40e_aq_set_vsi_unicast_promiscuous(hw, i40e->i40e_vsi_id,
231 on, NULL, B_FALSE);
232 if (ret != I40E_SUCCESS) {
233 i40e_error(i40e, "failed to %s unicast promiscuity on "
234 "the default VSI: %d", on == B_TRUE ? "enable" : "disable",
235 ret);
236 err = EIO;
237 goto done;
241 * If we have a non-zero mcast_promisc_count, then it has already been
242 * enabled or we need to leave it that way and not touch it.
244 if (i40e->i40e_mcast_promisc_count > 0) {
245 i40e->i40e_promisc_on = on;
246 goto done;
249 ret = i40e_aq_set_vsi_multicast_promiscuous(hw, i40e->i40e_vsi_id,
250 on, NULL);
251 if (ret != I40E_SUCCESS) {
252 i40e_error(i40e, "failed to %s multicast promiscuity on "
253 "the default VSI: %d", on == B_TRUE ? "enable" : "disable",
254 ret);
257 * Try our best to put us back into a state that MAC expects us
258 * to be in.
260 ret = i40e_aq_set_vsi_unicast_promiscuous(hw, i40e->i40e_vsi_id,
261 !on, NULL, B_FALSE);
262 if (ret != I40E_SUCCESS) {
263 i40e_error(i40e, "failed to %s unicast promiscuity on "
264 "the default VSI after toggling multicast failed: "
265 "%d", on == B_TRUE ? "disable" : "enable", ret);
268 err = EIO;
269 goto done;
270 } else {
271 i40e->i40e_promisc_on = on;
274 done:
275 mutex_exit(&i40e->i40e_general_lock);
276 return (err);
280 * See the big theory statement in i40e_main.c for multicast address management.
282 static int
283 i40e_multicast_add(i40e_t *i40e, const uint8_t *multicast_address)
285 struct i40e_hw *hw = &i40e->i40e_hw_space;
286 struct i40e_aqc_add_macvlan_element_data filt;
287 i40e_maddr_t *mc;
288 int ret;
290 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
292 if (i40e->i40e_resources.ifr_nmcastfilt_used ==
293 i40e->i40e_resources.ifr_nmcastfilt) {
294 if (i40e->i40e_mcast_promisc_count == 0 &&
295 i40e->i40e_promisc_on == B_FALSE) {
296 ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
297 i40e->i40e_vsi_id, B_TRUE, NULL);
298 if (ret != I40E_SUCCESS) {
299 i40e_error(i40e, "failed to enable multicast "
300 "promiscuous mode on VSI %d: %d",
301 i40e->i40e_vsi_id, ret);
302 return (EIO);
305 i40e->i40e_mcast_promisc_count++;
306 return (0);
309 mc = &i40e->i40e_maddrs[i40e->i40e_resources.ifr_nmcastfilt_used];
310 bzero(&filt, sizeof (filt));
311 bcopy(multicast_address, filt.mac_addr, ETHERADDRL);
312 filt.flags = I40E_AQC_MACVLAN_ADD_HASH_MATCH |
313 I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
315 if ((ret = i40e_aq_add_macvlan(hw, i40e->i40e_vsi_id, &filt, 1,
316 NULL)) != I40E_SUCCESS) {
317 i40e_error(i40e, "failed to add mac address "
318 "%2x:%2x:%2x:%2x:%2x:%2x to multicast filter: %d",
319 multicast_address[0], multicast_address[1],
320 multicast_address[2], multicast_address[3],
321 multicast_address[4], multicast_address[5],
322 ret);
323 return (EIO);
326 bcopy(multicast_address, mc->ima_mac, ETHERADDRL);
327 i40e->i40e_resources.ifr_nmcastfilt_used++;
328 return (0);
332 * See the big theory statement in i40e_main.c for multicast address management.
334 static int
335 i40e_multicast_remove(i40e_t *i40e, const uint8_t *multicast_address)
337 int i, ret;
338 struct i40e_hw *hw = &i40e->i40e_hw_space;
340 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
342 for (i = 0; i < i40e->i40e_resources.ifr_nmcastfilt_used; i++) {
343 struct i40e_aqc_remove_macvlan_element_data filt;
344 int last;
346 if (bcmp(multicast_address, i40e->i40e_maddrs[i].ima_mac,
347 ETHERADDRL) != 0) {
348 continue;
351 bzero(&filt, sizeof (filt));
352 bcopy(multicast_address, filt.mac_addr, ETHERADDRL);
353 filt.flags = I40E_AQC_MACVLAN_DEL_HASH_MATCH |
354 I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
356 if (i40e_aq_remove_macvlan(hw, i40e->i40e_vsi_id,
357 &filt, 1, NULL) != I40E_SUCCESS) {
358 i40e_error(i40e, "failed to remove mac address "
359 "%2x:%2x:%2x:%2x:%2x:%2x from multicast "
360 "filter: %d",
361 multicast_address[0], multicast_address[1],
362 multicast_address[2], multicast_address[3],
363 multicast_address[4], multicast_address[5],
364 filt.error_code);
365 return (EIO);
368 last = i40e->i40e_resources.ifr_nmcastfilt_used - 1;
369 if (i != last) {
370 bcopy(&i40e->i40e_maddrs[last], &i40e->i40e_maddrs[i],
371 sizeof (i40e_maddr_t));
372 bzero(&i40e->i40e_maddrs[last], sizeof (i40e_maddr_t));
375 ASSERT(i40e->i40e_resources.ifr_nmcastfilt_used > 0);
376 i40e->i40e_resources.ifr_nmcastfilt_used--;
377 return (0);
380 if (i40e->i40e_mcast_promisc_count > 0) {
381 if (i40e->i40e_mcast_promisc_count == 1 &&
382 i40e->i40e_promisc_on == B_FALSE) {
383 ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
384 i40e->i40e_vsi_id, B_FALSE, NULL);
385 if (ret != I40E_SUCCESS) {
386 i40e_error(i40e, "failed to disable "
387 "multicast promiscuous mode on VSI %d: %d",
388 i40e->i40e_vsi_id, ret);
389 return (EIO);
392 i40e->i40e_mcast_promisc_count--;
394 return (0);
397 return (ENOENT);
400 static int
401 i40e_m_multicast(void *arg, boolean_t add, const uint8_t *multicast_address)
403 i40e_t *i40e = arg;
404 int rc;
406 mutex_enter(&i40e->i40e_general_lock);
408 if (i40e->i40e_state & I40E_SUSPENDED) {
409 mutex_exit(&i40e->i40e_general_lock);
410 return (ECANCELED);
413 if (add == B_TRUE) {
414 rc = i40e_multicast_add(i40e, multicast_address);
415 } else {
416 rc = i40e_multicast_remove(i40e, multicast_address);
419 mutex_exit(&i40e->i40e_general_lock);
420 return (rc);
423 /* ARGSUSED */
424 static void
425 i40e_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
428 * At this time, we don't support toggling i40e into loopback mode. It's
429 * questionable how much value this has when there's no clear way to
430 * toggle this behavior from a supported way in userland.
432 miocnak(q, mp, 0, EINVAL);
435 static int
436 i40e_ring_start(mac_ring_driver_t rh, uint64_t gen_num)
438 i40e_trqpair_t *itrq = (i40e_trqpair_t *)rh;
441 * GLDv3 requires we keep track of a generation number, as it uses
442 * that number to keep track of whether or not a ring is active.
444 mutex_enter(&itrq->itrq_rx_lock);
445 itrq->itrq_rxgen = gen_num;
446 mutex_exit(&itrq->itrq_rx_lock);
447 return (0);
450 /* ARGSUSED */
451 static int
452 i40e_rx_ring_intr_enable(mac_intr_handle_t intrh)
454 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
455 i40e_t *i40e = itrq->itrq_i40e;
457 mutex_enter(&itrq->itrq_rx_lock);
458 ASSERT(itrq->itrq_intr_poll == B_TRUE);
459 i40e_intr_rx_queue_enable(i40e, itrq->itrq_index);
460 itrq->itrq_intr_poll = B_FALSE;
461 mutex_exit(&itrq->itrq_rx_lock);
463 return (0);
466 /* ARGSUSED */
467 static int
468 i40e_rx_ring_intr_disable(mac_intr_handle_t intrh)
470 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
471 i40e_t *i40e = itrq->itrq_i40e;
473 mutex_enter(&itrq->itrq_rx_lock);
474 i40e_intr_rx_queue_disable(i40e, itrq->itrq_index);
475 itrq->itrq_intr_poll = B_TRUE;
476 mutex_exit(&itrq->itrq_rx_lock);
478 return (0);
481 /* ARGSUSED */
482 static void
483 i40e_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
484 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
486 i40e_t *i40e = arg;
487 mac_intr_t *mintr = &infop->mri_intr;
488 i40e_trqpair_t *itrq = &(i40e->i40e_trqpairs[ring_index]);
491 * Note the group index here is expected to be -1 due to the fact that
492 * we're not actually grouping things tx-wise at this time.
494 ASSERT(group_index == -1);
495 ASSERT(ring_index < i40e->i40e_num_trqpairs);
497 itrq->itrq_mactxring = rh;
498 infop->mri_driver = (mac_ring_driver_t)itrq;
499 infop->mri_start = NULL;
500 infop->mri_stop = NULL;
501 infop->mri_tx = i40e_ring_tx;
502 infop->mri_stat = i40e_tx_ring_stat;
505 * We only provide the handle in cases where we have MSI-X interrupts,
506 * to indicate that we'd actually support retargetting.
508 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
509 mintr->mi_ddi_handle =
510 i40e->i40e_intr_handles[itrq->itrq_tx_intrvec];
514 /* ARGSUSED */
515 static void
516 i40e_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
517 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
519 i40e_t *i40e = arg;
520 mac_intr_t *mintr = &infop->mri_intr;
521 i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[ring_index];
524 * We assert the group number and ring index to help sanity check
525 * ourselves and mark that we'll need to rework this when we have
526 * multiple groups.
528 ASSERT3S(group_index, ==, 0);
529 ASSERT3S(ring_index, <, i40e->i40e_num_trqpairs);
531 itrq->itrq_macrxring = rh;
532 infop->mri_driver = (mac_ring_driver_t)itrq;
533 infop->mri_start = i40e_ring_start;
534 infop->mri_stop = NULL;
535 infop->mri_poll = i40e_ring_rx_poll;
536 infop->mri_stat = i40e_rx_ring_stat;
537 mintr->mi_handle = (mac_intr_handle_t)itrq;
538 mintr->mi_enable = i40e_rx_ring_intr_enable;
539 mintr->mi_disable = i40e_rx_ring_intr_disable;
542 * We only provide the handle in cases where we have MSI-X interrupts,
543 * to indicate that we'd actually support retargetting.
545 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
546 mintr->mi_ddi_handle =
547 i40e->i40e_intr_handles[itrq->itrq_rx_intrvec];
551 /* ARGSUSED */
552 static void
553 i40e_fill_rx_group(void *arg, mac_ring_type_t rtype, const int index,
554 mac_group_info_t *infop, mac_group_handle_t gh)
556 i40e_t *i40e = arg;
558 if (rtype != MAC_RING_TYPE_RX)
559 return;
562 * Note, this is a simplified view of a group, given that we only have a
563 * single group and a single ring at the moment. We'll want to expand
564 * upon this as we leverage more hardware functionality.
566 i40e->i40e_rx_group_handle = gh;
567 infop->mgi_driver = (mac_group_driver_t)i40e;
568 infop->mgi_start = NULL;
569 infop->mgi_stop = NULL;
570 infop->mgi_addmac = i40e_group_add_mac;
571 infop->mgi_remmac = i40e_group_remove_mac;
573 ASSERT(i40e->i40e_num_rx_groups == I40E_GROUP_MAX);
574 infop->mgi_count = i40e->i40e_num_trqpairs;
577 static boolean_t
578 i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
580 i40e_t *i40e = arg;
581 mac_capab_rings_t *cap_rings;
583 switch (cap) {
584 case MAC_CAPAB_HCKSUM: {
585 uint32_t *txflags = cap_data;
587 *txflags = 0;
588 if (i40e->i40e_tx_hcksum_enable == B_TRUE)
589 *txflags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
590 break;
593 case MAC_CAPAB_RINGS:
594 cap_rings = cap_data;
595 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
596 switch (cap_rings->mr_type) {
597 case MAC_RING_TYPE_TX:
599 * Note, saying we have no rings, but some number of
600 * groups indicates to MAC that it should create
601 * psuedo-groups with one for each TX ring. This may not
602 * be the long term behavior we want, but it'll work for
603 * now.
605 cap_rings->mr_gnum = 0;
606 cap_rings->mr_rnum = i40e->i40e_num_trqpairs;
607 cap_rings->mr_rget = i40e_fill_tx_ring;
608 cap_rings->mr_gget = NULL;
609 cap_rings->mr_gaddring = NULL;
610 cap_rings->mr_gremring = NULL;
611 break;
612 case MAC_RING_TYPE_RX:
613 cap_rings->mr_rnum = i40e->i40e_num_trqpairs;
614 cap_rings->mr_rget = i40e_fill_rx_ring;
615 cap_rings->mr_gnum = I40E_GROUP_MAX;
616 cap_rings->mr_gget = i40e_fill_rx_group;
617 cap_rings->mr_gaddring = NULL;
618 cap_rings->mr_gremring = NULL;
619 break;
620 default:
621 return (B_FALSE);
623 break;
624 default:
625 return (B_FALSE);
628 return (B_TRUE);
631 /* ARGSUSED */
632 static int
633 i40e_m_setprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize,
634 const void *pr_val)
636 int ret;
637 long val;
638 char *eptr;
640 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
642 if ((ret = ddi_strtol(pr_val, &eptr, 10, &val)) != 0 ||
643 *eptr != '\0') {
644 return (ret);
647 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
648 if (val < I40E_MIN_RX_DMA_THRESH ||
649 val > I40E_MAX_RX_DMA_THRESH) {
650 return (EINVAL);
652 i40e->i40e_rx_dma_min = (uint32_t)val;
653 return (0);
656 if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
657 if (val < I40E_MIN_TX_DMA_THRESH ||
658 val > I40E_MAX_TX_DMA_THRESH) {
659 return (EINVAL);
661 i40e->i40e_tx_dma_min = (uint32_t)val;
662 return (0);
665 if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
666 if (val < I40E_MIN_ITR ||
667 val > I40E_MAX_ITR) {
668 return (EINVAL);
670 i40e->i40e_rx_itr = (uint32_t)val;
671 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr);
672 return (0);
675 if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
676 if (val < I40E_MIN_ITR ||
677 val > I40E_MAX_ITR) {
678 return (EINVAL);
680 i40e->i40e_tx_itr = (uint32_t)val;
681 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr);
682 return (0);
685 if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
686 if (val < I40E_MIN_ITR ||
687 val > I40E_MAX_ITR) {
688 return (EINVAL);
690 i40e->i40e_tx_itr = (uint32_t)val;
691 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER,
692 i40e->i40e_other_itr);
693 return (0);
696 return (ENOTSUP);
699 static int
700 i40e_m_getprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize,
701 void *pr_val)
703 uint32_t val;
705 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
707 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
708 val = i40e->i40e_rx_dma_min;
709 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
710 val = i40e->i40e_tx_dma_min;
711 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
712 val = i40e->i40e_rx_itr;
713 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
714 val = i40e->i40e_tx_itr;
715 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
716 val = i40e->i40e_other_itr;
717 } else {
718 return (ENOTSUP);
721 if (snprintf(pr_val, pr_valsize, "%d", val) >= pr_valsize)
722 return (ERANGE);
723 return (0);
727 * Annoyingly for private properties MAC seems to ignore default values that
728 * aren't strings. That means that we have to translate all of these into
729 * uint32_t's and instead we size the buffer to be large enough to hold a
730 * uint32_t.
732 /* ARGSUSED */
733 static void
734 i40e_m_propinfo_private(i40e_t *i40e, const char *pr_name,
735 mac_prop_info_handle_t prh)
737 char buf[64];
738 uint32_t def;
740 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
741 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
742 def = I40E_DEF_RX_DMA_THRESH;
743 mac_prop_info_set_range_uint32(prh,
744 I40E_MIN_RX_DMA_THRESH,
745 I40E_MAX_RX_DMA_THRESH);
746 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
747 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
748 def = I40E_DEF_TX_DMA_THRESH;
749 mac_prop_info_set_range_uint32(prh,
750 I40E_MIN_TX_DMA_THRESH,
751 I40E_MAX_TX_DMA_THRESH);
752 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
753 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
754 def = I40E_DEF_RX_ITR;
755 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
756 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
757 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
758 def = I40E_DEF_TX_ITR;
759 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
760 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
761 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
762 def = I40E_DEF_OTHER_ITR;
763 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
764 } else {
765 return;
768 (void) snprintf(buf, sizeof (buf), "%d", def);
769 mac_prop_info_set_default_str(prh, buf);
772 static int
773 i40e_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
774 uint_t pr_valsize, const void *pr_val)
776 uint32_t new_mtu;
777 i40e_t *i40e = arg;
778 int ret = 0;
780 mutex_enter(&i40e->i40e_general_lock);
781 if (i40e->i40e_state & I40E_SUSPENDED) {
782 mutex_exit(&i40e->i40e_general_lock);
783 return (ECANCELED);
786 switch (pr_num) {
788 * These properties are always read-only across every device.
790 case MAC_PROP_DUPLEX:
791 case MAC_PROP_SPEED:
792 case MAC_PROP_STATUS:
793 case MAC_PROP_ADV_100FDX_CAP:
794 case MAC_PROP_ADV_1000FDX_CAP:
795 case MAC_PROP_ADV_10GFDX_CAP:
796 case MAC_PROP_ADV_25GFDX_CAP:
797 case MAC_PROP_ADV_40GFDX_CAP:
798 ret = ENOTSUP;
799 break;
801 * These are read-only at this time as we don't support configuring
802 * auto-negotiation. See the theory statement in i40e_main.c.
804 case MAC_PROP_EN_100FDX_CAP:
805 case MAC_PROP_EN_1000FDX_CAP:
806 case MAC_PROP_EN_10GFDX_CAP:
807 case MAC_PROP_EN_25GFDX_CAP:
808 case MAC_PROP_EN_40GFDX_CAP:
809 case MAC_PROP_AUTONEG:
810 case MAC_PROP_FLOWCTRL:
811 ret = ENOTSUP;
812 break;
814 case MAC_PROP_MTU:
815 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
816 if (new_mtu == i40e->i40e_sdu)
817 break;
819 if (new_mtu < I40E_MIN_MTU ||
820 new_mtu > I40E_MAX_MTU) {
821 ret = EINVAL;
822 break;
825 if (i40e->i40e_state & I40E_STARTED) {
826 ret = EBUSY;
827 break;
830 ret = mac_maxsdu_update(i40e->i40e_mac_hdl, new_mtu);
831 if (ret == 0) {
832 i40e->i40e_sdu = new_mtu;
833 i40e_update_mtu(i40e);
835 break;
837 case MAC_PROP_PRIVATE:
838 ret = i40e_m_setprop_private(i40e, pr_name, pr_valsize, pr_val);
839 break;
840 default:
841 ret = ENOTSUP;
842 break;
845 mutex_exit(&i40e->i40e_general_lock);
846 return (ret);
849 static int
850 i40e_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
851 uint_t pr_valsize, void *pr_val)
853 i40e_t *i40e = arg;
854 uint64_t speed;
855 int ret = 0;
856 uint8_t *u8;
857 link_flowctrl_t fctl;
859 mutex_enter(&i40e->i40e_general_lock);
861 switch (pr_num) {
862 case MAC_PROP_DUPLEX:
863 if (pr_valsize < sizeof (link_duplex_t)) {
864 ret = EOVERFLOW;
865 break;
867 bcopy(&i40e->i40e_link_duplex, pr_val, sizeof (link_duplex_t));
868 break;
869 case MAC_PROP_SPEED:
870 if (pr_valsize < sizeof (uint64_t)) {
871 ret = EOVERFLOW;
872 break;
874 speed = i40e->i40e_link_speed * 1000000ULL;
875 bcopy(&speed, pr_val, sizeof (speed));
876 break;
877 case MAC_PROP_STATUS:
878 if (pr_valsize < sizeof (link_state_t)) {
879 ret = EOVERFLOW;
880 break;
882 bcopy(&i40e->i40e_link_state, pr_val, sizeof (link_state_t));
883 break;
884 case MAC_PROP_AUTONEG:
885 if (pr_valsize < sizeof (uint8_t)) {
886 ret = EOVERFLOW;
887 break;
889 u8 = pr_val;
890 *u8 = 1;
891 break;
892 case MAC_PROP_FLOWCTRL:
894 * Because we don't currently support hardware flow control, we
895 * just hardcode this to be none.
897 if (pr_valsize < sizeof (link_flowctrl_t)) {
898 ret = EOVERFLOW;
899 break;
901 fctl = LINK_FLOWCTRL_NONE;
902 bcopy(&fctl, pr_val, sizeof (link_flowctrl_t));
903 break;
904 case MAC_PROP_MTU:
905 if (pr_valsize < sizeof (uint32_t)) {
906 ret = EOVERFLOW;
907 break;
909 bcopy(&i40e->i40e_sdu, pr_val, sizeof (uint32_t));
910 break;
913 * Because we don't let users control the speeds we may auto-negotiate
914 * to, the values of the ADV_ and EN_ will always be the same.
916 case MAC_PROP_ADV_100FDX_CAP:
917 case MAC_PROP_EN_100FDX_CAP:
918 if (pr_valsize < sizeof (uint8_t)) {
919 ret = EOVERFLOW;
920 break;
922 u8 = pr_val;
923 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0;
924 break;
925 case MAC_PROP_ADV_1000FDX_CAP:
926 case MAC_PROP_EN_1000FDX_CAP:
927 if (pr_valsize < sizeof (uint8_t)) {
928 ret = EOVERFLOW;
929 break;
931 u8 = pr_val;
932 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0;
933 break;
934 case MAC_PROP_ADV_10GFDX_CAP:
935 case MAC_PROP_EN_10GFDX_CAP:
936 if (pr_valsize < sizeof (uint8_t)) {
937 ret = EOVERFLOW;
938 break;
940 u8 = pr_val;
941 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0;
942 break;
943 case MAC_PROP_ADV_25GFDX_CAP:
944 case MAC_PROP_EN_25GFDX_CAP:
945 if (pr_valsize < sizeof (uint8_t)) {
946 ret = EOVERFLOW;
947 break;
949 u8 = pr_val;
950 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0;
951 break;
952 case MAC_PROP_ADV_40GFDX_CAP:
953 case MAC_PROP_EN_40GFDX_CAP:
954 if (pr_valsize < sizeof (uint8_t)) {
955 ret = EOVERFLOW;
956 break;
958 u8 = pr_val;
959 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0;
960 break;
961 case MAC_PROP_PRIVATE:
962 ret = i40e_m_getprop_private(i40e, pr_name, pr_valsize, pr_val);
963 break;
964 default:
965 ret = ENOTSUP;
966 break;
969 mutex_exit(&i40e->i40e_general_lock);
971 return (ret);
974 static void
975 i40e_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
976 mac_prop_info_handle_t prh)
978 i40e_t *i40e = arg;
980 mutex_enter(&i40e->i40e_general_lock);
982 switch (pr_num) {
983 case MAC_PROP_DUPLEX:
984 case MAC_PROP_SPEED:
985 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
986 break;
987 case MAC_PROP_FLOWCTRL:
989 * At the moment, the driver doesn't support flow control, hence
990 * why this is set to read-only and none.
992 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
993 mac_prop_info_set_default_link_flowctrl(prh,
994 LINK_FLOWCTRL_NONE);
995 break;
996 case MAC_PROP_MTU:
997 mac_prop_info_set_range_uint32(prh, I40E_MIN_MTU, I40E_MAX_MTU);
998 break;
1001 * We set the defaults for these based upon the phy's ability to
1002 * support the speeds. Note, auto-negotiation is required for fiber,
1003 * hence it is read-only and always enabled. When we have access to
1004 * copper phys we can revisit this.
1006 case MAC_PROP_AUTONEG:
1007 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1008 mac_prop_info_set_default_uint8(prh, 1);
1009 break;
1010 case MAC_PROP_ADV_100FDX_CAP:
1011 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1012 mac_prop_info_set_default_uint8(prh,
1013 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0);
1014 break;
1015 case MAC_PROP_EN_100FDX_CAP:
1016 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1017 mac_prop_info_set_default_uint8(prh,
1018 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0);
1019 break;
1020 case MAC_PROP_ADV_1000FDX_CAP:
1021 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1022 mac_prop_info_set_default_uint8(prh,
1023 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0);
1024 break;
1025 case MAC_PROP_EN_1000FDX_CAP:
1026 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1027 mac_prop_info_set_default_uint8(prh,
1028 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0);
1029 break;
1030 case MAC_PROP_ADV_10GFDX_CAP:
1031 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1032 mac_prop_info_set_default_uint8(prh,
1033 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0);
1034 break;
1035 case MAC_PROP_EN_10GFDX_CAP:
1036 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1037 mac_prop_info_set_default_uint8(prh,
1038 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0);
1039 break;
1040 case MAC_PROP_ADV_25GFDX_CAP:
1041 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1042 mac_prop_info_set_default_uint8(prh,
1043 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0);
1044 break;
1045 case MAC_PROP_EN_25GFDX_CAP:
1046 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1047 mac_prop_info_set_default_uint8(prh,
1048 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0);
1049 break;
1050 case MAC_PROP_ADV_40GFDX_CAP:
1051 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1052 mac_prop_info_set_default_uint8(prh,
1053 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0);
1054 break;
1055 case MAC_PROP_EN_40GFDX_CAP:
1056 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1057 mac_prop_info_set_default_uint8(prh,
1058 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0);
1059 break;
1060 case MAC_PROP_PRIVATE:
1061 i40e_m_propinfo_private(i40e, pr_name, prh);
1062 break;
1063 default:
1064 break;
1067 mutex_exit(&i40e->i40e_general_lock);
1070 #define I40E_M_CALLBACK_FLAGS \
1071 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
1073 static mac_callbacks_t i40e_m_callbacks = {
1074 I40E_M_CALLBACK_FLAGS,
1075 i40e_m_stat,
1076 i40e_m_start,
1077 i40e_m_stop,
1078 i40e_m_promisc,
1079 i40e_m_multicast,
1080 NULL,
1081 NULL,
1082 NULL,
1083 i40e_m_ioctl,
1084 i40e_m_getcapab,
1085 NULL,
1086 NULL,
1087 i40e_m_setprop,
1088 i40e_m_getprop,
1089 i40e_m_propinfo
1092 boolean_t
1093 i40e_register_mac(i40e_t *i40e)
1095 struct i40e_hw *hw = &i40e->i40e_hw_space;
1096 int status;
1097 mac_register_t *mac = mac_alloc(MAC_VERSION);
1099 if (mac == NULL)
1100 return (B_FALSE);
1102 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1103 mac->m_driver = i40e;
1104 mac->m_dip = i40e->i40e_dip;
1105 mac->m_src_addr = hw->mac.addr;
1106 mac->m_callbacks = &i40e_m_callbacks;
1107 mac->m_min_sdu = 0;
1108 mac->m_max_sdu = i40e->i40e_sdu;
1109 mac->m_margin = VLAN_TAGSZ;
1110 mac->m_priv_props = i40e_priv_props;
1111 mac->m_v12n = MAC_VIRT_LEVEL1;
1113 status = mac_register(mac, &i40e->i40e_mac_hdl);
1114 if (status != 0)
1115 i40e_error(i40e, "mac_register() returned %d", status);
1116 mac_free(mac);
1118 return (status == 0);