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