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.
6 *
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.
10 */
11
12 /*
13 * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved.
14 * Copyright (c) 2018, Joyent, Inc.
15 * Copyright 2017 Tegile Systems, Inc. All rights reserved.
16 */
17
18 /*
19 * For more information, please see the big theory statement in i40e_main.c.
20 */
21
22 #include "i40e_sw.h"
23
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"
29
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
37 };
38
39 static int
i40e_group_remove_mac(void * arg,const uint8_t * mac_addr)40 i40e_group_remove_mac(void *arg, const uint8_t *mac_addr)
41 {
42 i40e_rx_group_t *rxg = arg;
43 i40e_t *i40e = rxg->irg_i40e;
44 struct i40e_aqc_remove_macvlan_element_data filt;
45 struct i40e_hw *hw = &i40e->i40e_hw_space;
46 int ret, i, last;
47 i40e_uaddr_t *iua;
48
49 if (I40E_IS_MULTICAST(mac_addr))
50 return (EINVAL);
51
52 mutex_enter(&i40e->i40e_general_lock);
53
54 if (i40e->i40e_state & I40E_SUSPENDED) {
55 ret = ECANCELED;
56 goto done;
57 }
58
59 for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) {
60 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac,
61 ETHERADDRL) == 0)
62 break;
63 }
64
65 if (i == i40e->i40e_resources.ifr_nmacfilt_used) {
66 ret = ENOENT;
67 goto done;
68 }
69
70 iua = &i40e->i40e_uaddrs[i];
71 ASSERT(i40e->i40e_resources.ifr_nmacfilt_used > 0);
72
73 bzero(&filt, sizeof (filt));
74 bcopy(mac_addr, filt.mac_addr, ETHERADDRL);
75 filt.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
76 I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
77
78 if (i40e_aq_remove_macvlan(hw, iua->iua_vsi, &filt, 1, NULL) !=
79 I40E_SUCCESS) {
80 i40e_error(i40e, "failed to remove mac address "
81 "%2x:%2x:%2x:%2x:%2x:%2x from unicast filter: %d",
82 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
83 mac_addr[4], mac_addr[5], filt.error_code);
84 ret = EIO;
85 goto done;
86 }
87
88 last = i40e->i40e_resources.ifr_nmacfilt_used - 1;
89 if (i != last) {
90 i40e_uaddr_t *src = &i40e->i40e_uaddrs[last];
91 bcopy(src, iua, sizeof (i40e_uaddr_t));
92 }
93
94 /*
95 * Set the multicast bit in the last one to indicate to ourselves that
96 * it's invalid.
97 */
98 bzero(&i40e->i40e_uaddrs[last], sizeof (i40e_uaddr_t));
99 i40e->i40e_uaddrs[last].iua_mac[0] = 0x01;
100 i40e->i40e_resources.ifr_nmacfilt_used--;
101 ret = 0;
102 done:
103 mutex_exit(&i40e->i40e_general_lock);
104
105 return (ret);
106 }
107
108 static int
i40e_group_add_mac(void * arg,const uint8_t * mac_addr)109 i40e_group_add_mac(void *arg, const uint8_t *mac_addr)
110 {
111 i40e_rx_group_t *rxg = arg;
112 i40e_t *i40e = rxg->irg_i40e;
113 struct i40e_hw *hw = &i40e->i40e_hw_space;
114 int i, ret;
115 i40e_uaddr_t *iua;
116 struct i40e_aqc_add_macvlan_element_data filt;
117
118 if (I40E_IS_MULTICAST(mac_addr))
119 return (EINVAL);
120
121 mutex_enter(&i40e->i40e_general_lock);
122 if (i40e->i40e_state & I40E_SUSPENDED) {
123 ret = ECANCELED;
124 goto done;
125 }
126
127 if (i40e->i40e_resources.ifr_nmacfilt ==
128 i40e->i40e_resources.ifr_nmacfilt_used) {
129 ret = ENOSPC;
130 goto done;
131 }
132
133 for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) {
134 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac,
135 ETHERADDRL) == 0) {
136 ret = EEXIST;
137 goto done;
138 }
139 }
140
141 bzero(&filt, sizeof (filt));
142 bcopy(mac_addr, filt.mac_addr, ETHERADDRL);
143 filt.flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH |
144 I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
145
146 if ((ret = i40e_aq_add_macvlan(hw, rxg->irg_vsi_seid, &filt, 1,
147 NULL)) != I40E_SUCCESS) {
148 i40e_error(i40e, "failed to add mac address "
149 "%2x:%2x:%2x:%2x:%2x:%2x to unicast filter: %d",
150 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
151 mac_addr[4], mac_addr[5], ret);
152 ret = EIO;
153 goto done;
154 }
155
156 iua = &i40e->i40e_uaddrs[i40e->i40e_resources.ifr_nmacfilt_used];
157 bcopy(mac_addr, iua->iua_mac, ETHERADDRL);
158 iua->iua_vsi = rxg->irg_vsi_seid;
159 i40e->i40e_resources.ifr_nmacfilt_used++;
160 ASSERT(i40e->i40e_resources.ifr_nmacfilt_used <=
161 i40e->i40e_resources.ifr_nmacfilt);
162 ret = 0;
163 done:
164 mutex_exit(&i40e->i40e_general_lock);
165 return (ret);
166 }
167
168 static int
i40e_m_start(void * arg)169 i40e_m_start(void *arg)
170 {
171 i40e_t *i40e = arg;
172 int rc = 0;
173
174 mutex_enter(&i40e->i40e_general_lock);
175 if (i40e->i40e_state & I40E_SUSPENDED) {
176 rc = ECANCELED;
177 goto done;
178 }
179
180 if (!i40e_start(i40e, B_TRUE)) {
181 rc = EIO;
182 goto done;
183 }
184
185 atomic_or_32(&i40e->i40e_state, I40E_STARTED);
186 done:
187 mutex_exit(&i40e->i40e_general_lock);
188
189 return (rc);
190 }
191
192 static void
i40e_m_stop(void * arg)193 i40e_m_stop(void *arg)
194 {
195 i40e_t *i40e = arg;
196
197 mutex_enter(&i40e->i40e_general_lock);
198
199 if (i40e->i40e_state & I40E_SUSPENDED)
200 goto done;
201
202 atomic_and_32(&i40e->i40e_state, ~I40E_STARTED);
203 i40e_stop(i40e, B_TRUE);
204 done:
205 mutex_exit(&i40e->i40e_general_lock);
206 }
207
208 /*
209 * Enable and disable promiscuous mode as requested. We have to toggle both
210 * unicast and multicast. Note that multicast may already be enabled due to the
211 * i40e_m_multicast may toggle it itself. See i40e_main.c for more information
212 * on this.
213 */
214 static int
i40e_m_promisc(void * arg,boolean_t on)215 i40e_m_promisc(void *arg, boolean_t on)
216 {
217 i40e_t *i40e = arg;
218 struct i40e_hw *hw = &i40e->i40e_hw_space;
219 int ret = 0, err = 0;
220
221 mutex_enter(&i40e->i40e_general_lock);
222 if (i40e->i40e_state & I40E_SUSPENDED) {
223 ret = ECANCELED;
224 goto done;
225 }
226
227
228 ret = i40e_aq_set_vsi_unicast_promiscuous(hw, I40E_DEF_VSI_SEID(i40e),
229 on, NULL, B_FALSE);
230 if (ret != I40E_SUCCESS) {
231 i40e_error(i40e, "failed to %s unicast promiscuity on "
232 "the default VSI: %d", on == B_TRUE ? "enable" : "disable",
233 ret);
234 err = EIO;
235 goto done;
236 }
237
238 /*
239 * If we have a non-zero mcast_promisc_count, then it has already been
240 * enabled or we need to leave it that way and not touch it.
241 */
242 if (i40e->i40e_mcast_promisc_count > 0) {
243 i40e->i40e_promisc_on = on;
244 goto done;
245 }
246
247 ret = i40e_aq_set_vsi_multicast_promiscuous(hw, I40E_DEF_VSI_SEID(i40e),
248 on, NULL);
249 if (ret != I40E_SUCCESS) {
250 i40e_error(i40e, "failed to %s multicast promiscuity on "
251 "the default VSI: %d", on == B_TRUE ? "enable" : "disable",
252 ret);
253
254 /*
255 * Try our best to put us back into a state that MAC expects us
256 * to be in.
257 */
258 ret = i40e_aq_set_vsi_unicast_promiscuous(hw,
259 I40E_DEF_VSI_SEID(i40e), !on, NULL, B_FALSE);
260 if (ret != I40E_SUCCESS) {
261 i40e_error(i40e, "failed to %s unicast promiscuity on "
262 "the default VSI after toggling multicast failed: "
263 "%d", on == B_TRUE ? "disable" : "enable", ret);
264 }
265
266 err = EIO;
267 goto done;
268 } else {
269 i40e->i40e_promisc_on = on;
270 }
271
272 done:
273 mutex_exit(&i40e->i40e_general_lock);
274 return (err);
275 }
276
277 /*
278 * See the big theory statement in i40e_main.c for multicast address management.
279 */
280 static int
i40e_multicast_add(i40e_t * i40e,const uint8_t * multicast_address)281 i40e_multicast_add(i40e_t *i40e, const uint8_t *multicast_address)
282 {
283 struct i40e_hw *hw = &i40e->i40e_hw_space;
284 struct i40e_aqc_add_macvlan_element_data filt;
285 i40e_maddr_t *mc;
286 int ret;
287
288 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
289
290 if (i40e->i40e_resources.ifr_nmcastfilt_used ==
291 i40e->i40e_resources.ifr_nmcastfilt) {
292 if (i40e->i40e_mcast_promisc_count == 0 &&
293 i40e->i40e_promisc_on == B_FALSE) {
294 ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
295 I40E_DEF_VSI_SEID(i40e), B_TRUE, NULL);
296 if (ret != I40E_SUCCESS) {
297 i40e_error(i40e, "failed to enable multicast "
298 "promiscuous mode on VSI %d: %d",
299 I40E_DEF_VSI_SEID(i40e), ret);
300 return (EIO);
301 }
302 }
303 i40e->i40e_mcast_promisc_count++;
304 return (0);
305 }
306
307 mc = &i40e->i40e_maddrs[i40e->i40e_resources.ifr_nmcastfilt_used];
308 bzero(&filt, sizeof (filt));
309 bcopy(multicast_address, filt.mac_addr, ETHERADDRL);
310 filt.flags = I40E_AQC_MACVLAN_ADD_HASH_MATCH |
311 I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
312
313 if ((ret = i40e_aq_add_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt, 1,
314 NULL)) != I40E_SUCCESS) {
315 i40e_error(i40e, "failed to add mac address "
316 "%2x:%2x:%2x:%2x:%2x:%2x to multicast filter: %d",
317 multicast_address[0], multicast_address[1],
318 multicast_address[2], multicast_address[3],
319 multicast_address[4], multicast_address[5],
320 ret);
321 return (EIO);
322 }
323
324 bcopy(multicast_address, mc->ima_mac, ETHERADDRL);
325 i40e->i40e_resources.ifr_nmcastfilt_used++;
326 return (0);
327 }
328
329 /*
330 * See the big theory statement in i40e_main.c for multicast address management.
331 */
332 static int
i40e_multicast_remove(i40e_t * i40e,const uint8_t * multicast_address)333 i40e_multicast_remove(i40e_t *i40e, const uint8_t *multicast_address)
334 {
335 int i, ret;
336 struct i40e_hw *hw = &i40e->i40e_hw_space;
337
338 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
339
340 for (i = 0; i < i40e->i40e_resources.ifr_nmcastfilt_used; i++) {
341 struct i40e_aqc_remove_macvlan_element_data filt;
342 int last;
343
344 if (bcmp(multicast_address, i40e->i40e_maddrs[i].ima_mac,
345 ETHERADDRL) != 0) {
346 continue;
347 }
348
349 bzero(&filt, sizeof (filt));
350 bcopy(multicast_address, filt.mac_addr, ETHERADDRL);
351 filt.flags = I40E_AQC_MACVLAN_DEL_HASH_MATCH |
352 I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
353
354 if (i40e_aq_remove_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt,
355 1, NULL) != I40E_SUCCESS) {
356 i40e_error(i40e, "failed to remove mac address "
357 "%2x:%2x:%2x:%2x:%2x:%2x from multicast "
358 "filter: %d",
359 multicast_address[0], multicast_address[1],
360 multicast_address[2], multicast_address[3],
361 multicast_address[4], multicast_address[5],
362 filt.error_code);
363 return (EIO);
364 }
365
366 last = i40e->i40e_resources.ifr_nmcastfilt_used - 1;
367 if (i != last) {
368 bcopy(&i40e->i40e_maddrs[last], &i40e->i40e_maddrs[i],
369 sizeof (i40e_maddr_t));
370 bzero(&i40e->i40e_maddrs[last], sizeof (i40e_maddr_t));
371 }
372
373 ASSERT(i40e->i40e_resources.ifr_nmcastfilt_used > 0);
374 i40e->i40e_resources.ifr_nmcastfilt_used--;
375 return (0);
376 }
377
378 if (i40e->i40e_mcast_promisc_count > 0) {
379 if (i40e->i40e_mcast_promisc_count == 1 &&
380 i40e->i40e_promisc_on == B_FALSE) {
381 ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
382 I40E_DEF_VSI_SEID(i40e), B_FALSE, NULL);
383 if (ret != I40E_SUCCESS) {
384 i40e_error(i40e, "failed to disable "
385 "multicast promiscuous mode on VSI %d: %d",
386 I40E_DEF_VSI_SEID(i40e), ret);
387 return (EIO);
388 }
389 }
390 i40e->i40e_mcast_promisc_count--;
391
392 return (0);
393 }
394
395 return (ENOENT);
396 }
397
398 static int
i40e_m_multicast(void * arg,boolean_t add,const uint8_t * multicast_address)399 i40e_m_multicast(void *arg, boolean_t add, const uint8_t *multicast_address)
400 {
401 i40e_t *i40e = arg;
402 int rc;
403
404 mutex_enter(&i40e->i40e_general_lock);
405
406 if (i40e->i40e_state & I40E_SUSPENDED) {
407 mutex_exit(&i40e->i40e_general_lock);
408 return (ECANCELED);
409 }
410
411 if (add == B_TRUE) {
412 rc = i40e_multicast_add(i40e, multicast_address);
413 } else {
414 rc = i40e_multicast_remove(i40e, multicast_address);
415 }
416
417 mutex_exit(&i40e->i40e_general_lock);
418 return (rc);
419 }
420
421 /* ARGSUSED */
422 static void
i40e_m_ioctl(void * arg,queue_t * q,mblk_t * mp)423 i40e_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
424 {
425 /*
426 * At this time, we don't support toggling i40e into loopback mode. It's
427 * questionable how much value this has when there's no clear way to
428 * toggle this behavior from a supported way in userland.
429 */
430 miocnak(q, mp, 0, EINVAL);
431 }
432
433 static int
i40e_ring_start(mac_ring_driver_t rh,uint64_t gen_num)434 i40e_ring_start(mac_ring_driver_t rh, uint64_t gen_num)
435 {
436 i40e_trqpair_t *itrq = (i40e_trqpair_t *)rh;
437
438 /*
439 * GLDv3 requires we keep track of a generation number, as it uses
440 * that number to keep track of whether or not a ring is active.
441 */
442 mutex_enter(&itrq->itrq_rx_lock);
443 itrq->itrq_rxgen = gen_num;
444 mutex_exit(&itrq->itrq_rx_lock);
445 return (0);
446 }
447
448 /* ARGSUSED */
449 static int
i40e_rx_ring_intr_enable(mac_intr_handle_t intrh)450 i40e_rx_ring_intr_enable(mac_intr_handle_t intrh)
451 {
452 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
453
454 mutex_enter(&itrq->itrq_rx_lock);
455 ASSERT(itrq->itrq_intr_poll == B_TRUE);
456 i40e_intr_rx_queue_enable(itrq);
457 itrq->itrq_intr_poll = B_FALSE;
458 mutex_exit(&itrq->itrq_rx_lock);
459
460 return (0);
461 }
462
463 /* ARGSUSED */
464 static int
i40e_rx_ring_intr_disable(mac_intr_handle_t intrh)465 i40e_rx_ring_intr_disable(mac_intr_handle_t intrh)
466 {
467 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
468
469 mutex_enter(&itrq->itrq_rx_lock);
470 i40e_intr_rx_queue_disable(itrq);
471 itrq->itrq_intr_poll = B_TRUE;
472 mutex_exit(&itrq->itrq_rx_lock);
473
474 return (0);
475 }
476
477 /* ARGSUSED */
478 static void
i40e_fill_tx_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)479 i40e_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
480 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
481 {
482 i40e_t *i40e = arg;
483 mac_intr_t *mintr = &infop->mri_intr;
484 i40e_trqpair_t *itrq = &(i40e->i40e_trqpairs[ring_index]);
485
486 /*
487 * Note the group index here is expected to be -1 due to the fact that
488 * we're not actually grouping things tx-wise at this time.
489 */
490 ASSERT(group_index == -1);
491 ASSERT(ring_index < i40e->i40e_num_trqpairs_per_vsi);
492
493 itrq->itrq_mactxring = rh;
494 infop->mri_driver = (mac_ring_driver_t)itrq;
495 infop->mri_start = NULL;
496 infop->mri_stop = NULL;
497 infop->mri_tx = i40e_ring_tx;
498 infop->mri_stat = i40e_tx_ring_stat;
499
500 /*
501 * We only provide the handle in cases where we have MSI-X interrupts,
502 * to indicate that we'd actually support retargetting.
503 */
504 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
505 mintr->mi_ddi_handle =
506 i40e->i40e_intr_handles[itrq->itrq_tx_intrvec];
507 }
508 }
509
510 /* ARGSUSED */
511 static void
i40e_fill_rx_ring(void * arg,mac_ring_type_t rtype,const int group_index,const int ring_index,mac_ring_info_t * infop,mac_ring_handle_t rh)512 i40e_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
513 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
514 {
515 i40e_t *i40e = arg;
516 mac_intr_t *mintr = &infop->mri_intr;
517 uint_t trqpair_index;
518 i40e_trqpair_t *itrq;
519
520 /* This assumes static groups. */
521 ASSERT3S(group_index, >=, 0);
522 ASSERT3S(ring_index, >=, 0);
523 trqpair_index = (group_index * i40e->i40e_num_trqpairs_per_vsi) +
524 ring_index;
525 ASSERT3U(trqpair_index, <, i40e->i40e_num_trqpairs);
526 itrq = &i40e->i40e_trqpairs[trqpair_index];
527
528 itrq->itrq_macrxring = rh;
529 infop->mri_driver = (mac_ring_driver_t)itrq;
530 infop->mri_start = i40e_ring_start;
531 infop->mri_stop = NULL;
532 infop->mri_poll = i40e_ring_rx_poll;
533 infop->mri_stat = i40e_rx_ring_stat;
534 mintr->mi_handle = (mac_intr_handle_t)itrq;
535 mintr->mi_enable = i40e_rx_ring_intr_enable;
536 mintr->mi_disable = i40e_rx_ring_intr_disable;
537
538 /*
539 * We only provide the handle in cases where we have MSI-X interrupts,
540 * to indicate that we'd actually support retargetting.
541 */
542 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
543 mintr->mi_ddi_handle =
544 i40e->i40e_intr_handles[itrq->itrq_rx_intrvec];
545 }
546 }
547
548 /* ARGSUSED */
549 static void
i40e_fill_rx_group(void * arg,mac_ring_type_t rtype,const int index,mac_group_info_t * infop,mac_group_handle_t gh)550 i40e_fill_rx_group(void *arg, mac_ring_type_t rtype, const int index,
551 mac_group_info_t *infop, mac_group_handle_t gh)
552 {
553 i40e_t *i40e = arg;
554 i40e_rx_group_t *rxg;
555
556 if (rtype != MAC_RING_TYPE_RX)
557 return;
558
559 rxg = &i40e->i40e_rx_groups[index];
560 rxg->irg_grp_hdl = gh;
561
562 infop->mgi_driver = (mac_group_driver_t)rxg;
563 infop->mgi_start = NULL;
564 infop->mgi_stop = NULL;
565 infop->mgi_addmac = i40e_group_add_mac;
566 infop->mgi_remmac = i40e_group_remove_mac;
567
568 ASSERT(i40e->i40e_num_rx_groups <= I40E_GROUP_MAX);
569 infop->mgi_count = i40e->i40e_num_trqpairs_per_vsi;
570 }
571
572 static int
i40e_transceiver_info(void * arg,uint_t id,mac_transceiver_info_t * infop)573 i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
574 {
575 boolean_t present, usable;
576 i40e_t *i40e = arg;
577
578 if (id != 0 || infop == NULL)
579 return (EINVAL);
580
581 mutex_enter(&i40e->i40e_general_lock);
582 switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) {
583 case I40E_MODULE_TYPE_SFP:
584 case I40E_MODULE_TYPE_QSFP:
585 break;
586 default:
587 mutex_exit(&i40e->i40e_general_lock);
588 return (ENOTSUP);
589 }
590
591 present = !!(i40e->i40e_hw_space.phy.link_info.link_info &
592 I40E_AQ_MEDIA_AVAILABLE);
593 if (present) {
594 usable = !!(i40e->i40e_hw_space.phy.link_info.an_info &
595 I40E_AQ_QUALIFIED_MODULE);
596 } else {
597 usable = B_FALSE;
598 }
599 mutex_exit(&i40e->i40e_general_lock);
600
601 mac_transceiver_info_set_usable(infop, usable);
602 mac_transceiver_info_set_present(infop, present);
603
604 return (0);
605 }
606
607 static int
i40e_transceiver_read(void * arg,uint_t id,uint_t page,void * buf,size_t nbytes,off_t offset,size_t * nread)608 i40e_transceiver_read(void *arg, uint_t id, uint_t page, void *buf,
609 size_t nbytes, off_t offset, size_t *nread)
610 {
611 i40e_t *i40e = arg;
612 struct i40e_hw *hw = &i40e->i40e_hw_space;
613 uint8_t *buf8 = buf;
614 size_t i;
615
616 if (id != 0 || buf == NULL || nbytes == 0 || nread == NULL ||
617 (page != 0xa0 && page != 0xa2) || offset < 0)
618 return (EINVAL);
619
620 /*
621 * Both supported pages have a length of 256 bytes, ensure nothing asks
622 * us to go beyond that.
623 */
624 if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) {
625 return (EINVAL);
626 }
627
628 mutex_enter(&i40e->i40e_general_lock);
629 switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) {
630 case I40E_MODULE_TYPE_SFP:
631 case I40E_MODULE_TYPE_QSFP:
632 break;
633 default:
634 mutex_exit(&i40e->i40e_general_lock);
635 return (ENOTSUP);
636 }
637
638 /*
639 * Make sure we have a sufficiently new firmware version to run this
640 * command. This was introduced in firmware API 1.7. This is apparently
641 * only supported on the XL710 MAC, not the XL722.
642 */
643 if (hw->mac.type != I40E_MAC_XL710 || hw->aq.api_maj_ver != 1 ||
644 hw->aq.api_min_ver < 7) {
645 mutex_exit(&i40e->i40e_general_lock);
646 return (ENOTSUP);
647 }
648
649 for (i = 0; i < nbytes; i++, offset++) {
650 enum i40e_status_code status;
651 uint32_t val;
652
653 status = i40e_aq_get_phy_register(hw,
654 I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, page, offset,
655 &val, NULL);
656 if (status != I40E_SUCCESS) {
657 mutex_exit(&i40e->i40e_general_lock);
658 return (EIO);
659 }
660
661 buf8[i] = (uint8_t)val;
662 }
663
664 mutex_exit(&i40e->i40e_general_lock);
665 *nread = nbytes;
666
667 return (0);
668 }
669
670 static int
i40e_gld_led_set(void * arg,mac_led_mode_t mode,uint_t flags)671 i40e_gld_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
672 {
673 i40e_t *i40e = arg;
674 struct i40e_hw *hw = &i40e->i40e_hw_space;
675
676 if (flags != 0)
677 return (EINVAL);
678
679 if (mode != MAC_LED_DEFAULT &&
680 mode != MAC_LED_IDENT &&
681 mode != MAC_LED_OFF &&
682 mode != MAC_LED_ON)
683 return (ENOTSUP);
684
685 if (mode != MAC_LED_DEFAULT && !i40e->i40e_led_saved) {
686 i40e->i40e_led_status = i40e_led_get(hw);
687 i40e->i40e_led_saved = B_TRUE;
688 }
689
690 switch (mode) {
691 case MAC_LED_DEFAULT:
692 if (i40e->i40e_led_saved) {
693 i40e_led_set(hw, i40e->i40e_led_status, B_FALSE);
694 i40e->i40e_led_status = 0;
695 i40e->i40e_led_saved = B_FALSE;
696 }
697 break;
698 case MAC_LED_IDENT:
699 i40e_led_set(hw, 0xf, B_TRUE);
700 break;
701 case MAC_LED_OFF:
702 i40e_led_set(hw, 0x0, B_FALSE);
703 break;
704 case MAC_LED_ON:
705 i40e_led_set(hw, 0xf, B_FALSE);
706 break;
707 default:
708 return (ENOTSUP);
709 }
710
711 return (0);
712 }
713
714 static boolean_t
i40e_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)715 i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
716 {
717 i40e_t *i40e = arg;
718 mac_capab_rings_t *cap_rings;
719 mac_capab_transceiver_t *mct;
720 mac_capab_led_t *mcl;
721
722 switch (cap) {
723 case MAC_CAPAB_HCKSUM: {
724 uint32_t *txflags = cap_data;
725
726 *txflags = 0;
727 if (i40e->i40e_tx_hcksum_enable == B_TRUE)
728 *txflags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
729 break;
730 }
731
732 case MAC_CAPAB_LSO: {
733 mac_capab_lso_t *cap_lso = cap_data;
734
735 if (i40e->i40e_tx_lso_enable == B_TRUE) {
736 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
737 cap_lso->lso_basic_tcp_ipv4.lso_max = I40E_LSO_MAXLEN;
738 } else {
739 return (B_FALSE);
740 }
741 break;
742 }
743
744 case MAC_CAPAB_RINGS:
745 cap_rings = cap_data;
746 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
747 switch (cap_rings->mr_type) {
748 case MAC_RING_TYPE_TX:
749 /*
750 * Note, saying we have no groups, but some
751 * number of rings indicates to MAC that it
752 * should create psuedo-groups with one for
753 * each TX ring. This may not be the long term
754 * behavior we want, but it'll work for now.
755 */
756 cap_rings->mr_gnum = 0;
757 cap_rings->mr_rnum = i40e->i40e_num_trqpairs_per_vsi;
758 cap_rings->mr_rget = i40e_fill_tx_ring;
759 cap_rings->mr_gget = NULL;
760 cap_rings->mr_gaddring = NULL;
761 cap_rings->mr_gremring = NULL;
762 break;
763 case MAC_RING_TYPE_RX:
764 cap_rings->mr_rnum = i40e->i40e_num_trqpairs;
765 cap_rings->mr_rget = i40e_fill_rx_ring;
766 cap_rings->mr_gnum = i40e->i40e_num_rx_groups;
767 cap_rings->mr_gget = i40e_fill_rx_group;
768 cap_rings->mr_gaddring = NULL;
769 cap_rings->mr_gremring = NULL;
770 break;
771 default:
772 return (B_FALSE);
773 }
774 break;
775 case MAC_CAPAB_TRANSCEIVER:
776 mct = cap_data;
777
778 /*
779 * Firmware doesn't have a great way of telling us in advance
780 * whether we'd expect a SFF transceiver. As such, we always
781 * advertise the support for this capability.
782 */
783 mct->mct_flags = 0;
784 mct->mct_ntransceivers = 1;
785 mct->mct_info = i40e_transceiver_info;
786 mct->mct_read = i40e_transceiver_read;
787
788 return (B_TRUE);
789 case MAC_CAPAB_LED:
790 mcl = cap_data;
791
792 mcl->mcl_flags = 0;
793 mcl->mcl_modes = MAC_LED_DEFAULT | MAC_LED_IDENT | MAC_LED_OFF |
794 MAC_LED_ON;
795 mcl->mcl_set = i40e_gld_led_set;
796 break;
797
798 default:
799 return (B_FALSE);
800 }
801
802 return (B_TRUE);
803 }
804
805 /* ARGSUSED */
806 static int
i40e_m_setprop_private(i40e_t * i40e,const char * pr_name,uint_t pr_valsize,const void * pr_val)807 i40e_m_setprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize,
808 const void *pr_val)
809 {
810 int ret;
811 long val;
812 char *eptr;
813
814 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
815
816 if ((ret = ddi_strtol(pr_val, &eptr, 10, &val)) != 0 ||
817 *eptr != '\0') {
818 return (ret);
819 }
820
821 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
822 if (val < I40E_MIN_RX_DMA_THRESH ||
823 val > I40E_MAX_RX_DMA_THRESH) {
824 return (EINVAL);
825 }
826 i40e->i40e_rx_dma_min = (uint32_t)val;
827 return (0);
828 }
829
830 if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
831 if (val < I40E_MIN_TX_DMA_THRESH ||
832 val > I40E_MAX_TX_DMA_THRESH) {
833 return (EINVAL);
834 }
835 i40e->i40e_tx_dma_min = (uint32_t)val;
836 return (0);
837 }
838
839 if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
840 if (val < I40E_MIN_ITR ||
841 val > I40E_MAX_ITR) {
842 return (EINVAL);
843 }
844 i40e->i40e_rx_itr = (uint32_t)val;
845 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr);
846 return (0);
847 }
848
849 if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
850 if (val < I40E_MIN_ITR ||
851 val > I40E_MAX_ITR) {
852 return (EINVAL);
853 }
854 i40e->i40e_tx_itr = (uint32_t)val;
855 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr);
856 return (0);
857 }
858
859 if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
860 if (val < I40E_MIN_ITR ||
861 val > I40E_MAX_ITR) {
862 return (EINVAL);
863 }
864 i40e->i40e_tx_itr = (uint32_t)val;
865 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER,
866 i40e->i40e_other_itr);
867 return (0);
868 }
869
870 return (ENOTSUP);
871 }
872
873 static int
i40e_m_getprop_private(i40e_t * i40e,const char * pr_name,uint_t pr_valsize,void * pr_val)874 i40e_m_getprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize,
875 void *pr_val)
876 {
877 uint32_t val;
878
879 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
880
881 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
882 val = i40e->i40e_rx_dma_min;
883 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
884 val = i40e->i40e_tx_dma_min;
885 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
886 val = i40e->i40e_rx_itr;
887 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
888 val = i40e->i40e_tx_itr;
889 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
890 val = i40e->i40e_other_itr;
891 } else {
892 return (ENOTSUP);
893 }
894
895 if (snprintf(pr_val, pr_valsize, "%d", val) >= pr_valsize)
896 return (ERANGE);
897 return (0);
898 }
899
900 /*
901 * Annoyingly for private properties MAC seems to ignore default values that
902 * aren't strings. That means that we have to translate all of these into
903 * uint32_t's and instead we size the buffer to be large enough to hold a
904 * uint32_t.
905 */
906 /* ARGSUSED */
907 static void
i40e_m_propinfo_private(i40e_t * i40e,const char * pr_name,mac_prop_info_handle_t prh)908 i40e_m_propinfo_private(i40e_t *i40e, const char *pr_name,
909 mac_prop_info_handle_t prh)
910 {
911 char buf[64];
912 uint32_t def;
913
914 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
915 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
916 def = I40E_DEF_RX_DMA_THRESH;
917 mac_prop_info_set_range_uint32(prh,
918 I40E_MIN_RX_DMA_THRESH,
919 I40E_MAX_RX_DMA_THRESH);
920 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
921 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
922 def = I40E_DEF_TX_DMA_THRESH;
923 mac_prop_info_set_range_uint32(prh,
924 I40E_MIN_TX_DMA_THRESH,
925 I40E_MAX_TX_DMA_THRESH);
926 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
927 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
928 def = I40E_DEF_RX_ITR;
929 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
930 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
931 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
932 def = I40E_DEF_TX_ITR;
933 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
934 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
935 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
936 def = I40E_DEF_OTHER_ITR;
937 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
938 } else {
939 return;
940 }
941
942 (void) snprintf(buf, sizeof (buf), "%d", def);
943 mac_prop_info_set_default_str(prh, buf);
944 }
945
946 static int
i40e_m_setprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,const void * pr_val)947 i40e_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
948 uint_t pr_valsize, const void *pr_val)
949 {
950 uint32_t new_mtu;
951 i40e_t *i40e = arg;
952 int ret = 0;
953
954 mutex_enter(&i40e->i40e_general_lock);
955 if (i40e->i40e_state & I40E_SUSPENDED) {
956 mutex_exit(&i40e->i40e_general_lock);
957 return (ECANCELED);
958 }
959
960 switch (pr_num) {
961 /*
962 * These properties are always read-only across every device.
963 */
964 case MAC_PROP_DUPLEX:
965 case MAC_PROP_SPEED:
966 case MAC_PROP_STATUS:
967 case MAC_PROP_ADV_100FDX_CAP:
968 case MAC_PROP_ADV_1000FDX_CAP:
969 case MAC_PROP_ADV_10GFDX_CAP:
970 case MAC_PROP_ADV_25GFDX_CAP:
971 case MAC_PROP_ADV_40GFDX_CAP:
972 ret = ENOTSUP;
973 break;
974 /*
975 * These are read-only at this time as we don't support configuring
976 * auto-negotiation. See the theory statement in i40e_main.c.
977 */
978 case MAC_PROP_EN_100FDX_CAP:
979 case MAC_PROP_EN_1000FDX_CAP:
980 case MAC_PROP_EN_10GFDX_CAP:
981 case MAC_PROP_EN_25GFDX_CAP:
982 case MAC_PROP_EN_40GFDX_CAP:
983 case MAC_PROP_AUTONEG:
984 case MAC_PROP_FLOWCTRL:
985 ret = ENOTSUP;
986 break;
987
988 case MAC_PROP_MTU:
989 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
990 if (new_mtu == i40e->i40e_sdu)
991 break;
992
993 if (new_mtu < I40E_MIN_MTU ||
994 new_mtu > I40E_MAX_MTU) {
995 ret = EINVAL;
996 break;
997 }
998
999 if (i40e->i40e_state & I40E_STARTED) {
1000 ret = EBUSY;
1001 break;
1002 }
1003
1004 ret = mac_maxsdu_update(i40e->i40e_mac_hdl, new_mtu);
1005 if (ret == 0) {
1006 i40e->i40e_sdu = new_mtu;
1007 i40e_update_mtu(i40e);
1008 }
1009 break;
1010
1011 case MAC_PROP_PRIVATE:
1012 ret = i40e_m_setprop_private(i40e, pr_name, pr_valsize, pr_val);
1013 break;
1014 default:
1015 ret = ENOTSUP;
1016 break;
1017 }
1018
1019 mutex_exit(&i40e->i40e_general_lock);
1020 return (ret);
1021 }
1022
1023 static int
i40e_m_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)1024 i40e_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1025 uint_t pr_valsize, void *pr_val)
1026 {
1027 i40e_t *i40e = arg;
1028 uint64_t speed;
1029 int ret = 0;
1030 uint8_t *u8;
1031 link_flowctrl_t fctl;
1032
1033 mutex_enter(&i40e->i40e_general_lock);
1034
1035 switch (pr_num) {
1036 case MAC_PROP_DUPLEX:
1037 if (pr_valsize < sizeof (link_duplex_t)) {
1038 ret = EOVERFLOW;
1039 break;
1040 }
1041 bcopy(&i40e->i40e_link_duplex, pr_val, sizeof (link_duplex_t));
1042 break;
1043 case MAC_PROP_SPEED:
1044 if (pr_valsize < sizeof (uint64_t)) {
1045 ret = EOVERFLOW;
1046 break;
1047 }
1048 speed = i40e->i40e_link_speed * 1000000ULL;
1049 bcopy(&speed, pr_val, sizeof (speed));
1050 break;
1051 case MAC_PROP_STATUS:
1052 if (pr_valsize < sizeof (link_state_t)) {
1053 ret = EOVERFLOW;
1054 break;
1055 }
1056 bcopy(&i40e->i40e_link_state, pr_val, sizeof (link_state_t));
1057 break;
1058 case MAC_PROP_AUTONEG:
1059 if (pr_valsize < sizeof (uint8_t)) {
1060 ret = EOVERFLOW;
1061 break;
1062 }
1063 u8 = pr_val;
1064 *u8 = 1;
1065 break;
1066 case MAC_PROP_FLOWCTRL:
1067 /*
1068 * Because we don't currently support hardware flow control, we
1069 * just hardcode this to be none.
1070 */
1071 if (pr_valsize < sizeof (link_flowctrl_t)) {
1072 ret = EOVERFLOW;
1073 break;
1074 }
1075 fctl = LINK_FLOWCTRL_NONE;
1076 bcopy(&fctl, pr_val, sizeof (link_flowctrl_t));
1077 break;
1078 case MAC_PROP_MTU:
1079 if (pr_valsize < sizeof (uint32_t)) {
1080 ret = EOVERFLOW;
1081 break;
1082 }
1083 bcopy(&i40e->i40e_sdu, pr_val, sizeof (uint32_t));
1084 break;
1085
1086 /*
1087 * Because we don't let users control the speeds we may auto-negotiate
1088 * to, the values of the ADV_ and EN_ will always be the same.
1089 */
1090 case MAC_PROP_ADV_100FDX_CAP:
1091 case MAC_PROP_EN_100FDX_CAP:
1092 if (pr_valsize < sizeof (uint8_t)) {
1093 ret = EOVERFLOW;
1094 break;
1095 }
1096 u8 = pr_val;
1097 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0;
1098 break;
1099 case MAC_PROP_ADV_1000FDX_CAP:
1100 case MAC_PROP_EN_1000FDX_CAP:
1101 if (pr_valsize < sizeof (uint8_t)) {
1102 ret = EOVERFLOW;
1103 break;
1104 }
1105 u8 = pr_val;
1106 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0;
1107 break;
1108 case MAC_PROP_ADV_10GFDX_CAP:
1109 case MAC_PROP_EN_10GFDX_CAP:
1110 if (pr_valsize < sizeof (uint8_t)) {
1111 ret = EOVERFLOW;
1112 break;
1113 }
1114 u8 = pr_val;
1115 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0;
1116 break;
1117 case MAC_PROP_ADV_25GFDX_CAP:
1118 case MAC_PROP_EN_25GFDX_CAP:
1119 if (pr_valsize < sizeof (uint8_t)) {
1120 ret = EOVERFLOW;
1121 break;
1122 }
1123 u8 = pr_val;
1124 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0;
1125 break;
1126 case MAC_PROP_ADV_40GFDX_CAP:
1127 case MAC_PROP_EN_40GFDX_CAP:
1128 if (pr_valsize < sizeof (uint8_t)) {
1129 ret = EOVERFLOW;
1130 break;
1131 }
1132 u8 = pr_val;
1133 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0;
1134 break;
1135 case MAC_PROP_PRIVATE:
1136 ret = i40e_m_getprop_private(i40e, pr_name, pr_valsize, pr_val);
1137 break;
1138 default:
1139 ret = ENOTSUP;
1140 break;
1141 }
1142
1143 mutex_exit(&i40e->i40e_general_lock);
1144
1145 return (ret);
1146 }
1147
1148 static void
i40e_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)1149 i40e_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1150 mac_prop_info_handle_t prh)
1151 {
1152 i40e_t *i40e = arg;
1153
1154 mutex_enter(&i40e->i40e_general_lock);
1155
1156 switch (pr_num) {
1157 case MAC_PROP_DUPLEX:
1158 case MAC_PROP_SPEED:
1159 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1160 break;
1161 case MAC_PROP_FLOWCTRL:
1162 /*
1163 * At the moment, the driver doesn't support flow control, hence
1164 * why this is set to read-only and none.
1165 */
1166 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1167 mac_prop_info_set_default_link_flowctrl(prh,
1168 LINK_FLOWCTRL_NONE);
1169 break;
1170 case MAC_PROP_MTU:
1171 mac_prop_info_set_range_uint32(prh, I40E_MIN_MTU, I40E_MAX_MTU);
1172 break;
1173
1174 /*
1175 * We set the defaults for these based upon the phy's ability to
1176 * support the speeds. Note, auto-negotiation is required for fiber,
1177 * hence it is read-only and always enabled. When we have access to
1178 * copper phys we can revisit this.
1179 */
1180 case MAC_PROP_AUTONEG:
1181 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1182 mac_prop_info_set_default_uint8(prh, 1);
1183 break;
1184 case MAC_PROP_ADV_100FDX_CAP:
1185 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1186 mac_prop_info_set_default_uint8(prh,
1187 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0);
1188 break;
1189 case MAC_PROP_EN_100FDX_CAP:
1190 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1191 mac_prop_info_set_default_uint8(prh,
1192 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0);
1193 break;
1194 case MAC_PROP_ADV_1000FDX_CAP:
1195 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1196 mac_prop_info_set_default_uint8(prh,
1197 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0);
1198 break;
1199 case MAC_PROP_EN_1000FDX_CAP:
1200 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1201 mac_prop_info_set_default_uint8(prh,
1202 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0);
1203 break;
1204 case MAC_PROP_ADV_10GFDX_CAP:
1205 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1206 mac_prop_info_set_default_uint8(prh,
1207 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0);
1208 break;
1209 case MAC_PROP_EN_10GFDX_CAP:
1210 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1211 mac_prop_info_set_default_uint8(prh,
1212 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0);
1213 break;
1214 case MAC_PROP_ADV_25GFDX_CAP:
1215 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1216 mac_prop_info_set_default_uint8(prh,
1217 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0);
1218 break;
1219 case MAC_PROP_EN_25GFDX_CAP:
1220 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1221 mac_prop_info_set_default_uint8(prh,
1222 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0);
1223 break;
1224 case MAC_PROP_ADV_40GFDX_CAP:
1225 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1226 mac_prop_info_set_default_uint8(prh,
1227 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0);
1228 break;
1229 case MAC_PROP_EN_40GFDX_CAP:
1230 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1231 mac_prop_info_set_default_uint8(prh,
1232 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0);
1233 break;
1234 case MAC_PROP_PRIVATE:
1235 i40e_m_propinfo_private(i40e, pr_name, prh);
1236 break;
1237 default:
1238 break;
1239 }
1240
1241 mutex_exit(&i40e->i40e_general_lock);
1242 }
1243
1244 #define I40E_M_CALLBACK_FLAGS \
1245 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
1246
1247 static mac_callbacks_t i40e_m_callbacks = {
1248 I40E_M_CALLBACK_FLAGS,
1249 i40e_m_stat,
1250 i40e_m_start,
1251 i40e_m_stop,
1252 i40e_m_promisc,
1253 i40e_m_multicast,
1254 NULL,
1255 NULL,
1256 NULL,
1257 i40e_m_ioctl,
1258 i40e_m_getcapab,
1259 NULL,
1260 NULL,
1261 i40e_m_setprop,
1262 i40e_m_getprop,
1263 i40e_m_propinfo
1264 };
1265
1266 boolean_t
i40e_register_mac(i40e_t * i40e)1267 i40e_register_mac(i40e_t *i40e)
1268 {
1269 struct i40e_hw *hw = &i40e->i40e_hw_space;
1270 int status;
1271 mac_register_t *mac = mac_alloc(MAC_VERSION);
1272
1273 if (mac == NULL)
1274 return (B_FALSE);
1275
1276 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1277 mac->m_driver = i40e;
1278 mac->m_dip = i40e->i40e_dip;
1279 mac->m_src_addr = hw->mac.addr;
1280 mac->m_callbacks = &i40e_m_callbacks;
1281 mac->m_min_sdu = 0;
1282 mac->m_max_sdu = i40e->i40e_sdu;
1283 mac->m_margin = VLAN_TAGSZ;
1284 mac->m_priv_props = i40e_priv_props;
1285 mac->m_v12n = MAC_VIRT_LEVEL1;
1286
1287 status = mac_register(mac, &i40e->i40e_mac_hdl);
1288 if (status != 0)
1289 i40e_error(i40e, "mac_register() returned %d", status);
1290 mac_free(mac);
1291
1292 return (status == 0);
1293 }
1294