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