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