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