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) 2017, 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_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;
47
48 if (I40E_IS_MULTICAST(mac_addr))
49 return (EINVAL);
50
51 mutex_enter(&i40e->i40e_general_lock);
52
53 if (i40e->i40e_state & I40E_SUSPENDED) {
54 ret = ECANCELED;
55 goto done;
56 }
57
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;
62 }
63
64 if (i == i40e->i40e_resources.ifr_nmacfilt_used) {
65 ret = ENOENT;
66 goto done;
67 }
68
69 iua = &i40e->i40e_uaddrs[i];
70 ASSERT(i40e->i40e_resources.ifr_nmacfilt_used > 0);
71
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;
76
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;
85 }
86
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));
91 }
92
93 /*
94 * Set the multicast bit in the last one to indicate to ourselves that
95 * it's invalid.
96 */
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);
103
104 return (ret);
105 }
106
107 static int
i40e_group_add_mac(void * arg,const uint8_t * mac_addr)108 i40e_group_add_mac(void *arg, const uint8_t *mac_addr)
109 {
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;
115
116 if (I40E_IS_MULTICAST(mac_addr))
117 return (EINVAL);
118
119 mutex_enter(&i40e->i40e_general_lock);
120 if (i40e->i40e_state & I40E_SUSPENDED) {
121 ret = ECANCELED;
122 goto done;
123 }
124
125 if (i40e->i40e_resources.ifr_nmacfilt ==
126 i40e->i40e_resources.ifr_nmacfilt_used) {
127 ret = ENOSPC;
128 goto done;
129 }
130
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;
136 }
137 }
138
139 /*
140 * Note, the general use of the i40e_vsi_id will have to be refactored
141 * when we have proper group support.
142 */
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;
147
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;
156 }
157
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);
168 }
169
170 static int
i40e_m_start(void * arg)171 i40e_m_start(void *arg)
172 {
173 i40e_t *i40e = arg;
174 int rc = 0;
175
176 mutex_enter(&i40e->i40e_general_lock);
177 if (i40e->i40e_state & I40E_SUSPENDED) {
178 rc = ECANCELED;
179 goto done;
180 }
181
182 if (!i40e_start(i40e, B_TRUE)) {
183 rc = EIO;
184 goto done;
185 }
186
187 atomic_or_32(&i40e->i40e_state, I40E_STARTED);
188 done:
189 mutex_exit(&i40e->i40e_general_lock);
190
191 return (rc);
192 }
193
194 static void
i40e_m_stop(void * arg)195 i40e_m_stop(void *arg)
196 {
197 i40e_t *i40e = arg;
198
199 mutex_enter(&i40e->i40e_general_lock);
200
201 if (i40e->i40e_state & I40E_SUSPENDED)
202 goto done;
203
204 atomic_and_32(&i40e->i40e_state, ~I40E_STARTED);
205 i40e_stop(i40e, B_TRUE);
206 done:
207 mutex_exit(&i40e->i40e_general_lock);
208 }
209
210 /*
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.
215 */
216 static int
i40e_m_promisc(void * arg,boolean_t on)217 i40e_m_promisc(void *arg, boolean_t on)
218 {
219 i40e_t *i40e = arg;
220 struct i40e_hw *hw = &i40e->i40e_hw_space;
221 int ret = 0, err = 0;
222
223 mutex_enter(&i40e->i40e_general_lock);
224 if (i40e->i40e_state & I40E_SUSPENDED) {
225 ret = ECANCELED;
226 goto done;
227 }
228
229
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;
238 }
239
240 /*
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.
243 */
244 if (i40e->i40e_mcast_promisc_count > 0) {
245 i40e->i40e_promisc_on = on;
246 goto done;
247 }
248
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);
255
256 /*
257 * Try our best to put us back into a state that MAC expects us
258 * to be in.
259 */
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);
266 }
267
268 err = EIO;
269 goto done;
270 } else {
271 i40e->i40e_promisc_on = on;
272 }
273
274 done:
275 mutex_exit(&i40e->i40e_general_lock);
276 return (err);
277 }
278
279 /*
280 * See the big theory statement in i40e_main.c for multicast address management.
281 */
282 static int
i40e_multicast_add(i40e_t * i40e,const uint8_t * multicast_address)283 i40e_multicast_add(i40e_t *i40e, const uint8_t *multicast_address)
284 {
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;
289
290 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
291
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);
303 }
304 }
305 i40e->i40e_mcast_promisc_count++;
306 return (0);
307 }
308
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;
314
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);
324 }
325
326 bcopy(multicast_address, mc->ima_mac, ETHERADDRL);
327 i40e->i40e_resources.ifr_nmcastfilt_used++;
328 return (0);
329 }
330
331 /*
332 * See the big theory statement in i40e_main.c for multicast address management.
333 */
334 static int
i40e_multicast_remove(i40e_t * i40e,const uint8_t * multicast_address)335 i40e_multicast_remove(i40e_t *i40e, const uint8_t *multicast_address)
336 {
337 int i, ret;
338 struct i40e_hw *hw = &i40e->i40e_hw_space;
339
340 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
341
342 for (i = 0; i < i40e->i40e_resources.ifr_nmcastfilt_used; i++) {
343 struct i40e_aqc_remove_macvlan_element_data filt;
344 int last;
345
346 if (bcmp(multicast_address, i40e->i40e_maddrs[i].ima_mac,
347 ETHERADDRL) != 0) {
348 continue;
349 }
350
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;
355
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);
366 }
367
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));
373 }
374
375 ASSERT(i40e->i40e_resources.ifr_nmcastfilt_used > 0);
376 i40e->i40e_resources.ifr_nmcastfilt_used--;
377 return (0);
378 }
379
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);
390 }
391 }
392 i40e->i40e_mcast_promisc_count--;
393
394 return (0);
395 }
396
397 return (ENOENT);
398 }
399
400 static int
i40e_m_multicast(void * arg,boolean_t add,const uint8_t * multicast_address)401 i40e_m_multicast(void *arg, boolean_t add, const uint8_t *multicast_address)
402 {
403 i40e_t *i40e = arg;
404 int rc;
405
406 mutex_enter(&i40e->i40e_general_lock);
407
408 if (i40e->i40e_state & I40E_SUSPENDED) {
409 mutex_exit(&i40e->i40e_general_lock);
410 return (ECANCELED);
411 }
412
413 if (add == B_TRUE) {
414 rc = i40e_multicast_add(i40e, multicast_address);
415 } else {
416 rc = i40e_multicast_remove(i40e, multicast_address);
417 }
418
419 mutex_exit(&i40e->i40e_general_lock);
420 return (rc);
421 }
422
423 /* ARGSUSED */
424 static void
i40e_m_ioctl(void * arg,queue_t * q,mblk_t * mp)425 i40e_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
426 {
427 /*
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.
431 */
432 miocnak(q, mp, 0, EINVAL);
433 }
434
435 static int
i40e_ring_start(mac_ring_driver_t rh,uint64_t gen_num)436 i40e_ring_start(mac_ring_driver_t rh, uint64_t gen_num)
437 {
438 i40e_trqpair_t *itrq = (i40e_trqpair_t *)rh;
439
440 /*
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.
443 */
444 mutex_enter(&itrq->itrq_rx_lock);
445 itrq->itrq_rxgen = gen_num;
446 mutex_exit(&itrq->itrq_rx_lock);
447 return (0);
448 }
449
450 /* ARGSUSED */
451 static int
i40e_rx_ring_intr_enable(mac_intr_handle_t intrh)452 i40e_rx_ring_intr_enable(mac_intr_handle_t intrh)
453 {
454 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
455
456 mutex_enter(&itrq->itrq_rx_lock);
457 ASSERT(itrq->itrq_intr_poll == B_TRUE);
458 i40e_intr_rx_queue_enable(itrq);
459 itrq->itrq_intr_poll = B_FALSE;
460 mutex_exit(&itrq->itrq_rx_lock);
461
462 return (0);
463 }
464
465 /* ARGSUSED */
466 static int
i40e_rx_ring_intr_disable(mac_intr_handle_t intrh)467 i40e_rx_ring_intr_disable(mac_intr_handle_t intrh)
468 {
469 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
470
471 mutex_enter(&itrq->itrq_rx_lock);
472 i40e_intr_rx_queue_disable(itrq);
473 itrq->itrq_intr_poll = B_TRUE;
474 mutex_exit(&itrq->itrq_rx_lock);
475
476 return (0);
477 }
478
479 /* ARGSUSED */
480 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)481 i40e_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
482 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
483 {
484 i40e_t *i40e = arg;
485 mac_intr_t *mintr = &infop->mri_intr;
486 i40e_trqpair_t *itrq = &(i40e->i40e_trqpairs[ring_index]);
487
488 /*
489 * Note the group index here is expected to be -1 due to the fact that
490 * we're not actually grouping things tx-wise at this time.
491 */
492 ASSERT(group_index == -1);
493 ASSERT(ring_index < i40e->i40e_num_trqpairs);
494
495 itrq->itrq_mactxring = rh;
496 infop->mri_driver = (mac_ring_driver_t)itrq;
497 infop->mri_start = NULL;
498 infop->mri_stop = NULL;
499 infop->mri_tx = i40e_ring_tx;
500 infop->mri_stat = i40e_tx_ring_stat;
501
502 /*
503 * We only provide the handle in cases where we have MSI-X interrupts,
504 * to indicate that we'd actually support retargetting.
505 */
506 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
507 mintr->mi_ddi_handle =
508 i40e->i40e_intr_handles[itrq->itrq_tx_intrvec];
509 }
510 }
511
512 /* ARGSUSED */
513 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)514 i40e_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
515 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
516 {
517 i40e_t *i40e = arg;
518 mac_intr_t *mintr = &infop->mri_intr;
519 i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[ring_index];
520
521 /*
522 * We assert the group number and ring index to help sanity check
523 * ourselves and mark that we'll need to rework this when we have
524 * multiple groups.
525 */
526 ASSERT3S(group_index, ==, 0);
527 ASSERT3S(ring_index, <, i40e->i40e_num_trqpairs);
528
529 itrq->itrq_macrxring = rh;
530 infop->mri_driver = (mac_ring_driver_t)itrq;
531 infop->mri_start = i40e_ring_start;
532 infop->mri_stop = NULL;
533 infop->mri_poll = i40e_ring_rx_poll;
534 infop->mri_stat = i40e_rx_ring_stat;
535 mintr->mi_handle = (mac_intr_handle_t)itrq;
536 mintr->mi_enable = i40e_rx_ring_intr_enable;
537 mintr->mi_disable = i40e_rx_ring_intr_disable;
538
539 /*
540 * We only provide the handle in cases where we have MSI-X interrupts,
541 * to indicate that we'd actually support retargetting.
542 */
543 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
544 mintr->mi_ddi_handle =
545 i40e->i40e_intr_handles[itrq->itrq_rx_intrvec];
546 }
547 }
548
549 /* ARGSUSED */
550 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)551 i40e_fill_rx_group(void *arg, mac_ring_type_t rtype, const int index,
552 mac_group_info_t *infop, mac_group_handle_t gh)
553 {
554 i40e_t *i40e = arg;
555
556 if (rtype != MAC_RING_TYPE_RX)
557 return;
558
559 /*
560 * Note, this is a simplified view of a group, given that we only have a
561 * single group and a single ring at the moment. We'll want to expand
562 * upon this as we leverage more hardware functionality.
563 */
564 i40e->i40e_rx_group_handle = gh;
565 infop->mgi_driver = (mac_group_driver_t)i40e;
566 infop->mgi_start = NULL;
567 infop->mgi_stop = NULL;
568 infop->mgi_addmac = i40e_group_add_mac;
569 infop->mgi_remmac = i40e_group_remove_mac;
570
571 ASSERT(i40e->i40e_num_rx_groups == I40E_GROUP_MAX);
572 infop->mgi_count = i40e->i40e_num_trqpairs;
573 }
574
575 static boolean_t
i40e_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)576 i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
577 {
578 i40e_t *i40e = arg;
579 mac_capab_rings_t *cap_rings;
580
581 switch (cap) {
582 case MAC_CAPAB_HCKSUM: {
583 uint32_t *txflags = cap_data;
584
585 *txflags = 0;
586 if (i40e->i40e_tx_hcksum_enable == B_TRUE)
587 *txflags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
588 break;
589 }
590
591 case MAC_CAPAB_RINGS:
592 cap_rings = cap_data;
593 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
594 switch (cap_rings->mr_type) {
595 case MAC_RING_TYPE_TX:
596 /*
597 * Note, saying we have no rings, but some number of
598 * groups indicates to MAC that it should create
599 * psuedo-groups with one for each TX ring. This may not
600 * be the long term behavior we want, but it'll work for
601 * now.
602 */
603 cap_rings->mr_gnum = 0;
604 cap_rings->mr_rnum = i40e->i40e_num_trqpairs;
605 cap_rings->mr_rget = i40e_fill_tx_ring;
606 cap_rings->mr_gget = NULL;
607 cap_rings->mr_gaddring = NULL;
608 cap_rings->mr_gremring = NULL;
609 break;
610 case MAC_RING_TYPE_RX:
611 cap_rings->mr_rnum = i40e->i40e_num_trqpairs;
612 cap_rings->mr_rget = i40e_fill_rx_ring;
613 cap_rings->mr_gnum = I40E_GROUP_MAX;
614 cap_rings->mr_gget = i40e_fill_rx_group;
615 cap_rings->mr_gaddring = NULL;
616 cap_rings->mr_gremring = NULL;
617 break;
618 default:
619 return (B_FALSE);
620 }
621 break;
622 default:
623 return (B_FALSE);
624 }
625
626 return (B_TRUE);
627 }
628
629 /* ARGSUSED */
630 static int
i40e_m_setprop_private(i40e_t * i40e,const char * pr_name,uint_t pr_valsize,const void * pr_val)631 i40e_m_setprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize,
632 const void *pr_val)
633 {
634 int ret;
635 long val;
636 char *eptr;
637
638 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
639
640 if ((ret = ddi_strtol(pr_val, &eptr, 10, &val)) != 0 ||
641 *eptr != '\0') {
642 return (ret);
643 }
644
645 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
646 if (val < I40E_MIN_RX_DMA_THRESH ||
647 val > I40E_MAX_RX_DMA_THRESH) {
648 return (EINVAL);
649 }
650 i40e->i40e_rx_dma_min = (uint32_t)val;
651 return (0);
652 }
653
654 if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
655 if (val < I40E_MIN_TX_DMA_THRESH ||
656 val > I40E_MAX_TX_DMA_THRESH) {
657 return (EINVAL);
658 }
659 i40e->i40e_tx_dma_min = (uint32_t)val;
660 return (0);
661 }
662
663 if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
664 if (val < I40E_MIN_ITR ||
665 val > I40E_MAX_ITR) {
666 return (EINVAL);
667 }
668 i40e->i40e_rx_itr = (uint32_t)val;
669 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr);
670 return (0);
671 }
672
673 if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
674 if (val < I40E_MIN_ITR ||
675 val > I40E_MAX_ITR) {
676 return (EINVAL);
677 }
678 i40e->i40e_tx_itr = (uint32_t)val;
679 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr);
680 return (0);
681 }
682
683 if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
684 if (val < I40E_MIN_ITR ||
685 val > I40E_MAX_ITR) {
686 return (EINVAL);
687 }
688 i40e->i40e_tx_itr = (uint32_t)val;
689 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER,
690 i40e->i40e_other_itr);
691 return (0);
692 }
693
694 return (ENOTSUP);
695 }
696
697 static int
i40e_m_getprop_private(i40e_t * i40e,const char * pr_name,uint_t pr_valsize,void * pr_val)698 i40e_m_getprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize,
699 void *pr_val)
700 {
701 uint32_t val;
702
703 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
704
705 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
706 val = i40e->i40e_rx_dma_min;
707 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
708 val = i40e->i40e_tx_dma_min;
709 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
710 val = i40e->i40e_rx_itr;
711 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
712 val = i40e->i40e_tx_itr;
713 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
714 val = i40e->i40e_other_itr;
715 } else {
716 return (ENOTSUP);
717 }
718
719 if (snprintf(pr_val, pr_valsize, "%d", val) >= pr_valsize)
720 return (ERANGE);
721 return (0);
722 }
723
724 /*
725 * Annoyingly for private properties MAC seems to ignore default values that
726 * aren't strings. That means that we have to translate all of these into
727 * uint32_t's and instead we size the buffer to be large enough to hold a
728 * uint32_t.
729 */
730 /* ARGSUSED */
731 static void
i40e_m_propinfo_private(i40e_t * i40e,const char * pr_name,mac_prop_info_handle_t prh)732 i40e_m_propinfo_private(i40e_t *i40e, const char *pr_name,
733 mac_prop_info_handle_t prh)
734 {
735 char buf[64];
736 uint32_t def;
737
738 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
739 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
740 def = I40E_DEF_RX_DMA_THRESH;
741 mac_prop_info_set_range_uint32(prh,
742 I40E_MIN_RX_DMA_THRESH,
743 I40E_MAX_RX_DMA_THRESH);
744 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
745 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
746 def = I40E_DEF_TX_DMA_THRESH;
747 mac_prop_info_set_range_uint32(prh,
748 I40E_MIN_TX_DMA_THRESH,
749 I40E_MAX_TX_DMA_THRESH);
750 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
751 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
752 def = I40E_DEF_RX_ITR;
753 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
754 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
755 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
756 def = I40E_DEF_TX_ITR;
757 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
758 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
759 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
760 def = I40E_DEF_OTHER_ITR;
761 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
762 } else {
763 return;
764 }
765
766 (void) snprintf(buf, sizeof (buf), "%d", def);
767 mac_prop_info_set_default_str(prh, buf);
768 }
769
770 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)771 i40e_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
772 uint_t pr_valsize, const void *pr_val)
773 {
774 uint32_t new_mtu;
775 i40e_t *i40e = arg;
776 int ret = 0;
777
778 mutex_enter(&i40e->i40e_general_lock);
779 if (i40e->i40e_state & I40E_SUSPENDED) {
780 mutex_exit(&i40e->i40e_general_lock);
781 return (ECANCELED);
782 }
783
784 switch (pr_num) {
785 /*
786 * These properties are always read-only across every device.
787 */
788 case MAC_PROP_DUPLEX:
789 case MAC_PROP_SPEED:
790 case MAC_PROP_STATUS:
791 case MAC_PROP_ADV_100FDX_CAP:
792 case MAC_PROP_ADV_1000FDX_CAP:
793 case MAC_PROP_ADV_10GFDX_CAP:
794 case MAC_PROP_ADV_25GFDX_CAP:
795 case MAC_PROP_ADV_40GFDX_CAP:
796 ret = ENOTSUP;
797 break;
798 /*
799 * These are read-only at this time as we don't support configuring
800 * auto-negotiation. See the theory statement in i40e_main.c.
801 */
802 case MAC_PROP_EN_100FDX_CAP:
803 case MAC_PROP_EN_1000FDX_CAP:
804 case MAC_PROP_EN_10GFDX_CAP:
805 case MAC_PROP_EN_25GFDX_CAP:
806 case MAC_PROP_EN_40GFDX_CAP:
807 case MAC_PROP_AUTONEG:
808 case MAC_PROP_FLOWCTRL:
809 ret = ENOTSUP;
810 break;
811
812 case MAC_PROP_MTU:
813 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
814 if (new_mtu == i40e->i40e_sdu)
815 break;
816
817 if (new_mtu < I40E_MIN_MTU ||
818 new_mtu > I40E_MAX_MTU) {
819 ret = EINVAL;
820 break;
821 }
822
823 if (i40e->i40e_state & I40E_STARTED) {
824 ret = EBUSY;
825 break;
826 }
827
828 ret = mac_maxsdu_update(i40e->i40e_mac_hdl, new_mtu);
829 if (ret == 0) {
830 i40e->i40e_sdu = new_mtu;
831 i40e_update_mtu(i40e);
832 }
833 break;
834
835 case MAC_PROP_PRIVATE:
836 ret = i40e_m_setprop_private(i40e, pr_name, pr_valsize, pr_val);
837 break;
838 default:
839 ret = ENOTSUP;
840 break;
841 }
842
843 mutex_exit(&i40e->i40e_general_lock);
844 return (ret);
845 }
846
847 static int
i40e_m_getprop(void * arg,const char * pr_name,mac_prop_id_t pr_num,uint_t pr_valsize,void * pr_val)848 i40e_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
849 uint_t pr_valsize, void *pr_val)
850 {
851 i40e_t *i40e = arg;
852 uint64_t speed;
853 int ret = 0;
854 uint8_t *u8;
855 link_flowctrl_t fctl;
856
857 mutex_enter(&i40e->i40e_general_lock);
858
859 switch (pr_num) {
860 case MAC_PROP_DUPLEX:
861 if (pr_valsize < sizeof (link_duplex_t)) {
862 ret = EOVERFLOW;
863 break;
864 }
865 bcopy(&i40e->i40e_link_duplex, pr_val, sizeof (link_duplex_t));
866 break;
867 case MAC_PROP_SPEED:
868 if (pr_valsize < sizeof (uint64_t)) {
869 ret = EOVERFLOW;
870 break;
871 }
872 speed = i40e->i40e_link_speed * 1000000ULL;
873 bcopy(&speed, pr_val, sizeof (speed));
874 break;
875 case MAC_PROP_STATUS:
876 if (pr_valsize < sizeof (link_state_t)) {
877 ret = EOVERFLOW;
878 break;
879 }
880 bcopy(&i40e->i40e_link_state, pr_val, sizeof (link_state_t));
881 break;
882 case MAC_PROP_AUTONEG:
883 if (pr_valsize < sizeof (uint8_t)) {
884 ret = EOVERFLOW;
885 break;
886 }
887 u8 = pr_val;
888 *u8 = 1;
889 break;
890 case MAC_PROP_FLOWCTRL:
891 /*
892 * Because we don't currently support hardware flow control, we
893 * just hardcode this to be none.
894 */
895 if (pr_valsize < sizeof (link_flowctrl_t)) {
896 ret = EOVERFLOW;
897 break;
898 }
899 fctl = LINK_FLOWCTRL_NONE;
900 bcopy(&fctl, pr_val, sizeof (link_flowctrl_t));
901 break;
902 case MAC_PROP_MTU:
903 if (pr_valsize < sizeof (uint32_t)) {
904 ret = EOVERFLOW;
905 break;
906 }
907 bcopy(&i40e->i40e_sdu, pr_val, sizeof (uint32_t));
908 break;
909
910 /*
911 * Because we don't let users control the speeds we may auto-negotiate
912 * to, the values of the ADV_ and EN_ will always be the same.
913 */
914 case MAC_PROP_ADV_100FDX_CAP:
915 case MAC_PROP_EN_100FDX_CAP:
916 if (pr_valsize < sizeof (uint8_t)) {
917 ret = EOVERFLOW;
918 break;
919 }
920 u8 = pr_val;
921 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0;
922 break;
923 case MAC_PROP_ADV_1000FDX_CAP:
924 case MAC_PROP_EN_1000FDX_CAP:
925 if (pr_valsize < sizeof (uint8_t)) {
926 ret = EOVERFLOW;
927 break;
928 }
929 u8 = pr_val;
930 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0;
931 break;
932 case MAC_PROP_ADV_10GFDX_CAP:
933 case MAC_PROP_EN_10GFDX_CAP:
934 if (pr_valsize < sizeof (uint8_t)) {
935 ret = EOVERFLOW;
936 break;
937 }
938 u8 = pr_val;
939 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0;
940 break;
941 case MAC_PROP_ADV_25GFDX_CAP:
942 case MAC_PROP_EN_25GFDX_CAP:
943 if (pr_valsize < sizeof (uint8_t)) {
944 ret = EOVERFLOW;
945 break;
946 }
947 u8 = pr_val;
948 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0;
949 break;
950 case MAC_PROP_ADV_40GFDX_CAP:
951 case MAC_PROP_EN_40GFDX_CAP:
952 if (pr_valsize < sizeof (uint8_t)) {
953 ret = EOVERFLOW;
954 break;
955 }
956 u8 = pr_val;
957 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0;
958 break;
959 case MAC_PROP_PRIVATE:
960 ret = i40e_m_getprop_private(i40e, pr_name, pr_valsize, pr_val);
961 break;
962 default:
963 ret = ENOTSUP;
964 break;
965 }
966
967 mutex_exit(&i40e->i40e_general_lock);
968
969 return (ret);
970 }
971
972 static void
i40e_m_propinfo(void * arg,const char * pr_name,mac_prop_id_t pr_num,mac_prop_info_handle_t prh)973 i40e_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
974 mac_prop_info_handle_t prh)
975 {
976 i40e_t *i40e = arg;
977
978 mutex_enter(&i40e->i40e_general_lock);
979
980 switch (pr_num) {
981 case MAC_PROP_DUPLEX:
982 case MAC_PROP_SPEED:
983 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
984 break;
985 case MAC_PROP_FLOWCTRL:
986 /*
987 * At the moment, the driver doesn't support flow control, hence
988 * why this is set to read-only and none.
989 */
990 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
991 mac_prop_info_set_default_link_flowctrl(prh,
992 LINK_FLOWCTRL_NONE);
993 break;
994 case MAC_PROP_MTU:
995 mac_prop_info_set_range_uint32(prh, I40E_MIN_MTU, I40E_MAX_MTU);
996 break;
997
998 /*
999 * We set the defaults for these based upon the phy's ability to
1000 * support the speeds. Note, auto-negotiation is required for fiber,
1001 * hence it is read-only and always enabled. When we have access to
1002 * copper phys we can revisit this.
1003 */
1004 case MAC_PROP_AUTONEG:
1005 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1006 mac_prop_info_set_default_uint8(prh, 1);
1007 break;
1008 case MAC_PROP_ADV_100FDX_CAP:
1009 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1010 mac_prop_info_set_default_uint8(prh,
1011 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0);
1012 break;
1013 case MAC_PROP_EN_100FDX_CAP:
1014 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1015 mac_prop_info_set_default_uint8(prh,
1016 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0);
1017 break;
1018 case MAC_PROP_ADV_1000FDX_CAP:
1019 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1020 mac_prop_info_set_default_uint8(prh,
1021 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0);
1022 break;
1023 case MAC_PROP_EN_1000FDX_CAP:
1024 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1025 mac_prop_info_set_default_uint8(prh,
1026 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0);
1027 break;
1028 case MAC_PROP_ADV_10GFDX_CAP:
1029 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1030 mac_prop_info_set_default_uint8(prh,
1031 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0);
1032 break;
1033 case MAC_PROP_EN_10GFDX_CAP:
1034 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1035 mac_prop_info_set_default_uint8(prh,
1036 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0);
1037 break;
1038 case MAC_PROP_ADV_25GFDX_CAP:
1039 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1040 mac_prop_info_set_default_uint8(prh,
1041 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0);
1042 break;
1043 case MAC_PROP_EN_25GFDX_CAP:
1044 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1045 mac_prop_info_set_default_uint8(prh,
1046 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0);
1047 break;
1048 case MAC_PROP_ADV_40GFDX_CAP:
1049 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1050 mac_prop_info_set_default_uint8(prh,
1051 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0);
1052 break;
1053 case MAC_PROP_EN_40GFDX_CAP:
1054 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1055 mac_prop_info_set_default_uint8(prh,
1056 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0);
1057 break;
1058 case MAC_PROP_PRIVATE:
1059 i40e_m_propinfo_private(i40e, pr_name, prh);
1060 break;
1061 default:
1062 break;
1063 }
1064
1065 mutex_exit(&i40e->i40e_general_lock);
1066 }
1067
1068 #define I40E_M_CALLBACK_FLAGS \
1069 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
1070
1071 static mac_callbacks_t i40e_m_callbacks = {
1072 I40E_M_CALLBACK_FLAGS,
1073 i40e_m_stat,
1074 i40e_m_start,
1075 i40e_m_stop,
1076 i40e_m_promisc,
1077 i40e_m_multicast,
1078 NULL,
1079 NULL,
1080 NULL,
1081 i40e_m_ioctl,
1082 i40e_m_getcapab,
1083 NULL,
1084 NULL,
1085 i40e_m_setprop,
1086 i40e_m_getprop,
1087 i40e_m_propinfo
1088 };
1089
1090 boolean_t
i40e_register_mac(i40e_t * i40e)1091 i40e_register_mac(i40e_t *i40e)
1092 {
1093 struct i40e_hw *hw = &i40e->i40e_hw_space;
1094 int status;
1095 mac_register_t *mac = mac_alloc(MAC_VERSION);
1096
1097 if (mac == NULL)
1098 return (B_FALSE);
1099
1100 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1101 mac->m_driver = i40e;
1102 mac->m_dip = i40e->i40e_dip;
1103 mac->m_src_addr = hw->mac.addr;
1104 mac->m_callbacks = &i40e_m_callbacks;
1105 mac->m_min_sdu = 0;
1106 mac->m_max_sdu = i40e->i40e_sdu;
1107 mac->m_margin = VLAN_TAGSZ;
1108 mac->m_priv_props = i40e_priv_props;
1109 mac->m_v12n = MAC_VIRT_LEVEL1;
1110
1111 status = mac_register(mac, &i40e->i40e_mac_hdl);
1112 if (status != 0)
1113 i40e_error(i40e, "mac_register() returned %d", status);
1114 mac_free(mac);
1115
1116 return (status == 0);
1117 }
1118