1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * nxge_hio.c 29 * 30 * This file manages the virtualization resources for Neptune 31 * devices. That is, it implements a hybrid I/O (HIO) approach in the 32 * Solaris kernel, whereby a guest domain on an LDOMs server may 33 * request & use hardware resources from the service domain. 34 * 35 */ 36 37 #include <sys/mac_provider.h> 38 #include <sys/nxge/nxge_impl.h> 39 #include <sys/nxge/nxge_fzc.h> 40 #include <sys/nxge/nxge_rxdma.h> 41 #include <sys/nxge/nxge_txdma.h> 42 #include <sys/nxge/nxge_hio.h> 43 44 /* 45 * External prototypes 46 */ 47 extern npi_status_t npi_rxdma_dump_rdc_table(npi_handle_t, uint8_t); 48 49 /* The following function may be found in nxge_main.c */ 50 extern int nxge_m_mmac_remove(void *arg, int slot); 51 extern int nxge_m_mmac_add_g(void *arg, const uint8_t *maddr, int rdctbl, 52 boolean_t usetbl); 53 54 /* The following function may be found in nxge_[t|r]xdma.c */ 55 extern npi_status_t nxge_txdma_channel_disable(nxge_t *, int); 56 extern nxge_status_t nxge_disable_rxdma_channel(nxge_t *, uint16_t); 57 58 /* 59 * Local prototypes 60 */ 61 static void nxge_grp_dc_append(nxge_t *, nxge_grp_t *, nxge_hio_dc_t *); 62 static nxge_hio_dc_t *nxge_grp_dc_unlink(nxge_t *, nxge_grp_t *, int); 63 static void nxge_grp_dc_map(nxge_grp_t *group); 64 65 /* 66 * These functions are used by both service & guest domains to 67 * decide whether they're running in an LDOMs/XEN environment 68 * or not. If so, then the Hybrid I/O (HIO) module is initialized. 69 */ 70 71 /* 72 * nxge_get_environs 73 * 74 * Figure out if we are in a guest domain or not. 75 * 76 * Arguments: 77 * nxge 78 * 79 * Notes: 80 * 81 * Context: 82 * Any domain 83 */ 84 void 85 nxge_get_environs( 86 nxge_t *nxge) 87 { 88 char *string; 89 90 /* 91 * In the beginning, assume that we are running sans LDOMs/XEN. 92 */ 93 nxge->environs = SOLARIS_DOMAIN; 94 95 /* 96 * Are we a hybrid I/O (HIO) guest domain driver? 97 */ 98 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, nxge->dip, 99 DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 100 "niutype", &string)) == DDI_PROP_SUCCESS) { 101 if (strcmp(string, "n2niu") == 0) { 102 nxge->environs = SOLARIS_GUEST_DOMAIN; 103 /* So we can allocate properly-aligned memory. */ 104 nxge->niu_type = N2_NIU; 105 NXGE_DEBUG_MSG((nxge, HIO_CTL, 106 "Hybrid IO-capable guest domain")); 107 } 108 ddi_prop_free(string); 109 } 110 } 111 112 #if !defined(sun4v) 113 114 /* 115 * nxge_hio_init 116 * 117 * Initialize the HIO module of the NXGE driver. 118 * 119 * Arguments: 120 * nxge 121 * 122 * Notes: 123 * This is the non-hybrid I/O version of this function. 124 * 125 * Context: 126 * Any domain 127 */ 128 int 129 nxge_hio_init(nxge_t *nxge) 130 { 131 nxge_hio_data_t *nhd; 132 int i; 133 134 nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 135 if (nhd == NULL) { 136 nhd = KMEM_ZALLOC(sizeof (*nhd), KM_SLEEP); 137 MUTEX_INIT(&nhd->lock, NULL, MUTEX_DRIVER, NULL); 138 nhd->type = NXGE_HIO_TYPE_SERVICE; 139 nxge->nxge_hw_p->hio = (uintptr_t)nhd; 140 } 141 142 /* 143 * Initialize share and ring group structures. 144 */ 145 for (i = 0; i < NXGE_MAX_TDCS; i++) 146 nxge->tdc_is_shared[i] = B_FALSE; 147 148 for (i = 0; i < NXGE_MAX_TDC_GROUPS; i++) { 149 nxge->tx_hio_groups[i].ghandle = NULL; 150 nxge->tx_hio_groups[i].nxgep = nxge; 151 nxge->tx_hio_groups[i].type = MAC_RING_TYPE_TX; 152 nxge->tx_hio_groups[i].gindex = 0; 153 nxge->tx_hio_groups[i].sindex = 0; 154 } 155 156 for (i = 0; i < NXGE_MAX_RDC_GROUPS; i++) { 157 nxge->rx_hio_groups[i].ghandle = NULL; 158 nxge->rx_hio_groups[i].nxgep = nxge; 159 nxge->rx_hio_groups[i].type = MAC_RING_TYPE_RX; 160 nxge->rx_hio_groups[i].gindex = 0; 161 nxge->rx_hio_groups[i].sindex = 0; 162 nxge->rx_hio_groups[i].started = B_FALSE; 163 nxge->rx_hio_groups[i].port_default_grp = B_FALSE; 164 nxge->rx_hio_groups[i].rdctbl = -1; 165 nxge->rx_hio_groups[i].n_mac_addrs = 0; 166 } 167 168 nhd->hio.ldoms = B_FALSE; 169 170 return (NXGE_OK); 171 } 172 173 #endif 174 175 void 176 nxge_hio_uninit(nxge_t *nxge) 177 { 178 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 179 180 ASSERT(nxge->nxge_hw_p->ndevs == 0); 181 182 if (nhd != NULL) { 183 MUTEX_DESTROY(&nhd->lock); 184 KMEM_FREE(nhd, sizeof (*nhd)); 185 nxge->nxge_hw_p->hio = 0; 186 } 187 } 188 189 /* 190 * nxge_dci_map 191 * 192 * Map a DMA channel index to a channel number. 193 * 194 * Arguments: 195 * instance The instance number of the driver. 196 * type The type of channel this is: Tx or Rx. 197 * index The index to convert to a channel number 198 * 199 * Notes: 200 * This function is called by nxge_ndd.c:nxge_param_set_port_rdc() 201 * 202 * Context: 203 * Any domain 204 */ 205 int 206 nxge_dci_map( 207 nxge_t *nxge, 208 vpc_type_t type, 209 int index) 210 { 211 nxge_grp_set_t *set; 212 int dc; 213 214 switch (type) { 215 case VP_BOUND_TX: 216 set = &nxge->tx_set; 217 break; 218 case VP_BOUND_RX: 219 set = &nxge->rx_set; 220 break; 221 } 222 223 for (dc = 0; dc < NXGE_MAX_TDCS; dc++) { 224 if ((1 << dc) & set->owned.map) { 225 if (index == 0) 226 return (dc); 227 else 228 index--; 229 } 230 } 231 232 return (-1); 233 } 234 235 /* 236 * --------------------------------------------------------------------- 237 * These are the general-purpose DMA channel group functions. That is, 238 * these functions are used to manage groups of TDCs or RDCs in an HIO 239 * environment. 240 * 241 * But is also expected that in the future they will be able to manage 242 * Crossbow groups. 243 * --------------------------------------------------------------------- 244 */ 245 246 /* 247 * nxge_grp_cleanup(p_nxge_t nxge) 248 * 249 * Remove all outstanding groups. 250 * 251 * Arguments: 252 * nxge 253 */ 254 void 255 nxge_grp_cleanup(p_nxge_t nxge) 256 { 257 nxge_grp_set_t *set; 258 int i; 259 260 MUTEX_ENTER(&nxge->group_lock); 261 262 /* 263 * Find RX groups that need to be cleaned up. 264 */ 265 set = &nxge->rx_set; 266 for (i = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) { 267 if (set->group[i] != NULL) { 268 KMEM_FREE(set->group[i], sizeof (nxge_grp_t)); 269 set->group[i] = NULL; 270 } 271 } 272 273 /* 274 * Find TX groups that need to be cleaned up. 275 */ 276 set = &nxge->tx_set; 277 for (i = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) { 278 if (set->group[i] != NULL) { 279 KMEM_FREE(set->group[i], sizeof (nxge_grp_t)); 280 set->group[i] = NULL; 281 } 282 } 283 MUTEX_EXIT(&nxge->group_lock); 284 } 285 286 287 /* 288 * nxge_grp_add 289 * 290 * Add a group to an instance of NXGE. 291 * 292 * Arguments: 293 * nxge 294 * type Tx or Rx 295 * 296 * Notes: 297 * 298 * Context: 299 * Any domain 300 */ 301 nxge_grp_t * 302 nxge_grp_add( 303 nxge_t *nxge, 304 nxge_grp_type_t type) 305 { 306 nxge_grp_set_t *set; 307 nxge_grp_t *group; 308 int i; 309 310 group = KMEM_ZALLOC(sizeof (*group), KM_SLEEP); 311 group->nxge = nxge; 312 313 MUTEX_ENTER(&nxge->group_lock); 314 switch (type) { 315 case NXGE_TRANSMIT_GROUP: 316 case EXT_TRANSMIT_GROUP: 317 set = &nxge->tx_set; 318 break; 319 default: 320 set = &nxge->rx_set; 321 break; 322 } 323 324 group->type = type; 325 group->active = B_TRUE; 326 group->sequence = set->sequence++; 327 328 /* Find an empty slot for this logical group. */ 329 for (i = 0; i < NXGE_LOGICAL_GROUP_MAX; i++) { 330 if (set->group[i] == 0) { 331 group->index = i; 332 set->group[i] = group; 333 NXGE_DC_SET(set->lg.map, i); 334 set->lg.count++; 335 break; 336 } 337 } 338 MUTEX_EXIT(&nxge->group_lock); 339 340 NXGE_DEBUG_MSG((nxge, HIO_CTL, 341 "nxge_grp_add: %cgroup = %d.%d", 342 type == NXGE_TRANSMIT_GROUP ? 't' : 'r', 343 nxge->mac.portnum, group->sequence)); 344 345 return (group); 346 } 347 348 void 349 nxge_grp_remove( 350 nxge_t *nxge, 351 nxge_grp_t *group) /* The group to remove. */ 352 { 353 nxge_grp_set_t *set; 354 vpc_type_t type; 355 356 if (group == NULL) 357 return; 358 359 MUTEX_ENTER(&nxge->group_lock); 360 switch (group->type) { 361 case NXGE_TRANSMIT_GROUP: 362 case EXT_TRANSMIT_GROUP: 363 set = &nxge->tx_set; 364 break; 365 default: 366 set = &nxge->rx_set; 367 break; 368 } 369 370 if (set->group[group->index] != group) { 371 MUTEX_EXIT(&nxge->group_lock); 372 return; 373 } 374 375 set->group[group->index] = 0; 376 NXGE_DC_RESET(set->lg.map, group->index); 377 set->lg.count--; 378 379 /* While inside the mutex, deactivate <group>. */ 380 group->active = B_FALSE; 381 382 MUTEX_EXIT(&nxge->group_lock); 383 384 NXGE_DEBUG_MSG((nxge, HIO_CTL, 385 "nxge_grp_remove(%c.%d.%d) called", 386 group->type == NXGE_TRANSMIT_GROUP ? 't' : 'r', 387 nxge->mac.portnum, group->sequence)); 388 389 /* Now, remove any DCs which are still active. */ 390 switch (group->type) { 391 default: 392 type = VP_BOUND_TX; 393 break; 394 case NXGE_RECEIVE_GROUP: 395 case EXT_RECEIVE_GROUP: 396 type = VP_BOUND_RX; 397 } 398 399 while (group->dc) { 400 nxge_grp_dc_remove(nxge, type, group->dc->channel); 401 } 402 403 KMEM_FREE(group, sizeof (*group)); 404 } 405 406 /* 407 * nxge_grp_dc_add 408 * 409 * Add a DMA channel to a VR/Group. 410 * 411 * Arguments: 412 * nxge 413 * channel The channel to add. 414 * Notes: 415 * 416 * Context: 417 * Any domain 418 */ 419 /* ARGSUSED */ 420 int 421 nxge_grp_dc_add( 422 nxge_t *nxge, 423 nxge_grp_t *group, /* The group to add <channel> to. */ 424 vpc_type_t type, /* Rx or Tx */ 425 int channel) /* A physical/logical channel number */ 426 { 427 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 428 nxge_hio_dc_t *dc; 429 nxge_grp_set_t *set; 430 nxge_status_t status = NXGE_OK; 431 432 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_grp_dc_add")); 433 434 if (group == 0) 435 return (0); 436 437 switch (type) { 438 case VP_BOUND_TX: 439 set = &nxge->tx_set; 440 if (channel > NXGE_MAX_TDCS) { 441 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 442 "nxge_grp_dc_add: TDC = %d", channel)); 443 return (NXGE_ERROR); 444 } 445 break; 446 case VP_BOUND_RX: 447 set = &nxge->rx_set; 448 if (channel > NXGE_MAX_RDCS) { 449 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 450 "nxge_grp_dc_add: RDC = %d", channel)); 451 return (NXGE_ERROR); 452 } 453 break; 454 455 default: 456 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 457 "nxge_grp_dc_add: unknown type channel(%d)", channel)); 458 } 459 460 NXGE_DEBUG_MSG((nxge, HIO_CTL, 461 "nxge_grp_dc_add: %cgroup = %d.%d.%d, channel = %d", 462 type == VP_BOUND_TX ? 't' : 'r', 463 nxge->mac.portnum, group->sequence, group->count, channel)); 464 465 MUTEX_ENTER(&nxge->group_lock); 466 if (group->active != B_TRUE) { 467 /* We may be in the process of removing this group. */ 468 MUTEX_EXIT(&nxge->group_lock); 469 return (NXGE_ERROR); 470 } 471 MUTEX_EXIT(&nxge->group_lock); 472 473 if (!(dc = nxge_grp_dc_find(nxge, type, channel))) { 474 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 475 "nxge_grp_dc_add(%d): DC FIND failed", channel)); 476 return (NXGE_ERROR); 477 } 478 479 MUTEX_ENTER(&nhd->lock); 480 481 if (dc->group) { 482 MUTEX_EXIT(&nhd->lock); 483 /* This channel is already in use! */ 484 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 485 "nxge_grp_dc_add(%d): channel already in group", channel)); 486 return (NXGE_ERROR); 487 } 488 489 dc->next = 0; 490 dc->page = channel; 491 dc->channel = (nxge_channel_t)channel; 492 493 dc->type = type; 494 if (type == VP_BOUND_RX) { 495 dc->init = nxge_init_rxdma_channel; 496 dc->uninit = nxge_uninit_rxdma_channel; 497 } else { 498 dc->init = nxge_init_txdma_channel; 499 dc->uninit = nxge_uninit_txdma_channel; 500 } 501 502 dc->group = group; 503 504 if (isLDOMguest(nxge)) 505 (void) nxge_hio_ldsv_add(nxge, dc); 506 507 NXGE_DC_SET(set->owned.map, channel); 508 set->owned.count++; 509 510 MUTEX_EXIT(&nhd->lock); 511 512 if ((status = (*dc->init)(nxge, channel)) != NXGE_OK) { 513 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 514 "nxge_grp_dc_add(%d): channel init failed", channel)); 515 MUTEX_ENTER(&nhd->lock); 516 (void) memset(dc, 0, sizeof (*dc)); 517 NXGE_DC_RESET(set->owned.map, channel); 518 set->owned.count--; 519 MUTEX_EXIT(&nhd->lock); 520 return (NXGE_ERROR); 521 } 522 523 nxge_grp_dc_append(nxge, group, dc); 524 525 if (type == VP_BOUND_TX) { 526 MUTEX_ENTER(&nhd->lock); 527 nxge->tdc_is_shared[channel] = B_FALSE; 528 MUTEX_EXIT(&nhd->lock); 529 } 530 531 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_grp_dc_add")); 532 533 return ((int)status); 534 } 535 536 void 537 nxge_grp_dc_remove( 538 nxge_t *nxge, 539 vpc_type_t type, 540 int channel) 541 { 542 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 543 nxge_hio_dc_t *dc; 544 nxge_grp_set_t *set; 545 nxge_grp_t *group; 546 547 dc_uninit_t uninit; 548 549 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_grp_dc_remove")); 550 551 if ((dc = nxge_grp_dc_find(nxge, type, channel)) == 0) 552 goto nxge_grp_dc_remove_exit; 553 554 if ((dc->group == NULL) && (dc->next == 0) && 555 (dc->channel == 0) && (dc->page == 0) && (dc->type == 0)) { 556 goto nxge_grp_dc_remove_exit; 557 } 558 559 group = (nxge_grp_t *)dc->group; 560 561 if (isLDOMguest(nxge)) { 562 (void) nxge_hio_intr_remove(nxge, type, channel); 563 } 564 565 NXGE_DEBUG_MSG((nxge, HIO_CTL, 566 "DC remove: group = %d.%d.%d, %cdc %d", 567 nxge->mac.portnum, group->sequence, group->count, 568 type == VP_BOUND_TX ? 't' : 'r', dc->channel)); 569 570 MUTEX_ENTER(&nhd->lock); 571 572 set = dc->type == VP_BOUND_TX ? &nxge->tx_set : &nxge->rx_set; 573 574 /* Remove the DC from its group. */ 575 if (nxge_grp_dc_unlink(nxge, group, channel) != dc) { 576 MUTEX_EXIT(&nhd->lock); 577 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 578 "nxge_grp_dc_remove(%d) failed", channel)); 579 goto nxge_grp_dc_remove_exit; 580 } 581 582 uninit = dc->uninit; 583 channel = dc->channel; 584 585 NXGE_DC_RESET(set->owned.map, channel); 586 set->owned.count--; 587 588 (void) memset(dc, 0, sizeof (*dc)); 589 590 MUTEX_EXIT(&nhd->lock); 591 592 (*uninit)(nxge, channel); 593 594 nxge_grp_dc_remove_exit: 595 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_grp_dc_remove")); 596 } 597 598 nxge_hio_dc_t * 599 nxge_grp_dc_find( 600 nxge_t *nxge, 601 vpc_type_t type, /* Rx or Tx */ 602 int channel) 603 { 604 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 605 nxge_hio_dc_t *current; 606 607 current = (type == VP_BOUND_TX) ? &nhd->tdc[0] : &nhd->rdc[0]; 608 609 if (!isLDOMguest(nxge)) { 610 return (¤t[channel]); 611 } else { 612 /* We're in a guest domain. */ 613 int i, limit = (type == VP_BOUND_TX) ? 614 NXGE_MAX_TDCS : NXGE_MAX_RDCS; 615 616 MUTEX_ENTER(&nhd->lock); 617 for (i = 0; i < limit; i++, current++) { 618 if (current->channel == channel) { 619 if (current->vr && current->vr->nxge == 620 (uintptr_t)nxge) { 621 MUTEX_EXIT(&nhd->lock); 622 return (current); 623 } 624 } 625 } 626 MUTEX_EXIT(&nhd->lock); 627 } 628 629 return (0); 630 } 631 632 /* 633 * nxge_grp_dc_append 634 * 635 * Append a DMA channel to a group. 636 * 637 * Arguments: 638 * nxge 639 * group The group to append to 640 * dc The DMA channel to append 641 * 642 * Notes: 643 * 644 * Context: 645 * Any domain 646 */ 647 static 648 void 649 nxge_grp_dc_append( 650 nxge_t *nxge, 651 nxge_grp_t *group, 652 nxge_hio_dc_t *dc) 653 { 654 MUTEX_ENTER(&nxge->group_lock); 655 656 if (group->dc == 0) { 657 group->dc = dc; 658 } else { 659 nxge_hio_dc_t *current = group->dc; 660 do { 661 if (current->next == 0) { 662 current->next = dc; 663 break; 664 } 665 current = current->next; 666 } while (current); 667 } 668 669 NXGE_DC_SET(group->map, dc->channel); 670 671 nxge_grp_dc_map(group); 672 group->count++; 673 674 MUTEX_EXIT(&nxge->group_lock); 675 } 676 677 /* 678 * nxge_grp_dc_unlink 679 * 680 * Unlink a DMA channel fromits linked list (group). 681 * 682 * Arguments: 683 * nxge 684 * group The group (linked list) to unlink from 685 * dc The DMA channel to append 686 * 687 * Notes: 688 * 689 * Context: 690 * Any domain 691 */ 692 nxge_hio_dc_t * 693 nxge_grp_dc_unlink( 694 nxge_t *nxge, 695 nxge_grp_t *group, 696 int channel) 697 { 698 nxge_hio_dc_t *current, *previous; 699 700 MUTEX_ENTER(&nxge->group_lock); 701 702 if (group == NULL) { 703 MUTEX_EXIT(&nxge->group_lock); 704 return (0); 705 } 706 707 if ((current = group->dc) == 0) { 708 MUTEX_EXIT(&nxge->group_lock); 709 return (0); 710 } 711 712 previous = 0; 713 do { 714 if (current->channel == channel) { 715 if (previous) 716 previous->next = current->next; 717 else 718 group->dc = current->next; 719 break; 720 } 721 previous = current; 722 current = current->next; 723 } while (current); 724 725 if (current == 0) { 726 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 727 "DC unlink: DC %d not found", channel)); 728 } else { 729 current->next = 0; 730 current->group = 0; 731 732 NXGE_DC_RESET(group->map, channel); 733 group->count--; 734 } 735 736 nxge_grp_dc_map(group); 737 738 MUTEX_EXIT(&nxge->group_lock); 739 740 return (current); 741 } 742 743 /* 744 * nxge_grp_dc_map 745 * 746 * Map a linked list to an array of channel numbers. 747 * 748 * Arguments: 749 * nxge 750 * group The group to remap. 751 * 752 * Notes: 753 * It is expected that the caller will hold the correct mutex. 754 * 755 * Context: 756 * Service domain 757 */ 758 void 759 nxge_grp_dc_map( 760 nxge_grp_t *group) 761 { 762 nxge_channel_t *legend; 763 nxge_hio_dc_t *dc; 764 765 (void) memset(group->legend, 0, sizeof (group->legend)); 766 767 legend = group->legend; 768 dc = group->dc; 769 while (dc) { 770 *legend = dc->channel; 771 legend++; 772 dc = dc->next; 773 } 774 } 775 776 /* 777 * --------------------------------------------------------------------- 778 * These are HIO debugging functions. 779 * --------------------------------------------------------------------- 780 */ 781 782 /* 783 * nxge_delay 784 * 785 * Delay <seconds> number of seconds. 786 * 787 * Arguments: 788 * nxge 789 * group The group to append to 790 * dc The DMA channel to append 791 * 792 * Notes: 793 * This is a developer-only function. 794 * 795 * Context: 796 * Any domain 797 */ 798 void 799 nxge_delay( 800 int seconds) 801 { 802 delay(drv_usectohz(seconds * 1000000)); 803 } 804 805 static dmc_reg_name_t rx_names[] = { 806 { "RXDMA_CFIG1", 0 }, 807 { "RXDMA_CFIG2", 8 }, 808 { "RBR_CFIG_A", 0x10 }, 809 { "RBR_CFIG_B", 0x18 }, 810 { "RBR_KICK", 0x20 }, 811 { "RBR_STAT", 0x28 }, 812 { "RBR_HDH", 0x30 }, 813 { "RBR_HDL", 0x38 }, 814 { "RCRCFIG_A", 0x40 }, 815 { "RCRCFIG_B", 0x48 }, 816 { "RCRSTAT_A", 0x50 }, 817 { "RCRSTAT_B", 0x58 }, 818 { "RCRSTAT_C", 0x60 }, 819 { "RX_DMA_ENT_MSK", 0x68 }, 820 { "RX_DMA_CTL_STAT", 0x70 }, 821 { "RCR_FLSH", 0x78 }, 822 { "RXMISC", 0x90 }, 823 { "RX_DMA_CTL_STAT_DBG", 0x98 }, 824 { 0, -1 } 825 }; 826 827 static dmc_reg_name_t tx_names[] = { 828 { "Tx_RNG_CFIG", 0 }, 829 { "Tx_RNG_HDL", 0x10 }, 830 { "Tx_RNG_KICK", 0x18 }, 831 { "Tx_ENT_MASK", 0x20 }, 832 { "Tx_CS", 0x28 }, 833 { "TxDMA_MBH", 0x30 }, 834 { "TxDMA_MBL", 0x38 }, 835 { "TxDMA_PRE_ST", 0x40 }, 836 { "Tx_RNG_ERR_LOGH", 0x48 }, 837 { "Tx_RNG_ERR_LOGL", 0x50 }, 838 { "TDMC_INTR_DBG", 0x60 }, 839 { "Tx_CS_DBG", 0x68 }, 840 { 0, -1 } 841 }; 842 843 /* 844 * nxge_xx2str 845 * 846 * Translate a register address into a string. 847 * 848 * Arguments: 849 * offset The address of the register to translate. 850 * 851 * Notes: 852 * These are developer-only function. 853 * 854 * Context: 855 * Any domain 856 */ 857 const char * 858 nxge_rx2str( 859 int offset) 860 { 861 dmc_reg_name_t *reg = &rx_names[0]; 862 863 offset &= DMA_CSR_MASK; 864 865 while (reg->name) { 866 if (offset == reg->offset) 867 return (reg->name); 868 reg++; 869 } 870 871 return (0); 872 } 873 874 const char * 875 nxge_tx2str( 876 int offset) 877 { 878 dmc_reg_name_t *reg = &tx_names[0]; 879 880 offset &= DMA_CSR_MASK; 881 882 while (reg->name) { 883 if (offset == reg->offset) 884 return (reg->name); 885 reg++; 886 } 887 888 return (0); 889 } 890 891 /* 892 * nxge_ddi_perror 893 * 894 * Map a DDI error number to a string. 895 * 896 * Arguments: 897 * ddi_error The DDI error number to map. 898 * 899 * Notes: 900 * 901 * Context: 902 * Any domain 903 */ 904 const char * 905 nxge_ddi_perror( 906 int ddi_error) 907 { 908 switch (ddi_error) { 909 case DDI_SUCCESS: 910 return ("DDI_SUCCESS"); 911 case DDI_FAILURE: 912 return ("DDI_FAILURE"); 913 case DDI_NOT_WELL_FORMED: 914 return ("DDI_NOT_WELL_FORMED"); 915 case DDI_EAGAIN: 916 return ("DDI_EAGAIN"); 917 case DDI_EINVAL: 918 return ("DDI_EINVAL"); 919 case DDI_ENOTSUP: 920 return ("DDI_ENOTSUP"); 921 case DDI_EPENDING: 922 return ("DDI_EPENDING"); 923 case DDI_ENOMEM: 924 return ("DDI_ENOMEM"); 925 case DDI_EBUSY: 926 return ("DDI_EBUSY"); 927 case DDI_ETRANSPORT: 928 return ("DDI_ETRANSPORT"); 929 case DDI_ECONTEXT: 930 return ("DDI_ECONTEXT"); 931 default: 932 return ("Unknown error"); 933 } 934 } 935 936 /* 937 * --------------------------------------------------------------------- 938 * These are Sun4v HIO function definitions 939 * --------------------------------------------------------------------- 940 */ 941 942 #if defined(sun4v) 943 944 /* 945 * Local prototypes 946 */ 947 static nxge_hio_vr_t *nxge_hio_vr_share(nxge_t *); 948 static void nxge_hio_unshare(nxge_hio_vr_t *); 949 950 static int nxge_hio_addres(nxge_hio_vr_t *, mac_ring_type_t, uint64_t *); 951 static void nxge_hio_remres(nxge_hio_vr_t *, mac_ring_type_t, res_map_t); 952 953 static void nxge_hio_tdc_unshare(nxge_t *nxge, int dev_grpid, int channel); 954 static void nxge_hio_rdc_unshare(nxge_t *nxge, int dev_grpid, int channel); 955 static int nxge_hio_dc_share(nxge_t *, nxge_hio_vr_t *, mac_ring_type_t, int); 956 static void nxge_hio_dc_unshare(nxge_t *, nxge_hio_vr_t *, 957 mac_ring_type_t, int); 958 959 /* 960 * nxge_hio_init 961 * 962 * Initialize the HIO module of the NXGE driver. 963 * 964 * Arguments: 965 * nxge 966 * 967 * Notes: 968 * 969 * Context: 970 * Any domain 971 */ 972 int 973 nxge_hio_init(nxge_t *nxge) 974 { 975 nxge_hio_data_t *nhd; 976 int i, region; 977 978 nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 979 if (nhd == 0) { 980 nhd = KMEM_ZALLOC(sizeof (*nhd), KM_SLEEP); 981 MUTEX_INIT(&nhd->lock, NULL, MUTEX_DRIVER, NULL); 982 if (isLDOMguest(nxge)) 983 nhd->type = NXGE_HIO_TYPE_GUEST; 984 else 985 nhd->type = NXGE_HIO_TYPE_SERVICE; 986 nxge->nxge_hw_p->hio = (uintptr_t)nhd; 987 } 988 989 if ((nxge->environs == SOLARIS_DOMAIN) && 990 (nxge->niu_type == N2_NIU)) { 991 if (nxge->niu_hsvc_available == B_TRUE) { 992 hsvc_info_t *niu_hsvc = &nxge->niu_hsvc; 993 /* 994 * Versions supported now are: 995 * - major number >= 1 (NIU_MAJOR_VER). 996 */ 997 if ((niu_hsvc->hsvc_major >= NIU_MAJOR_VER) || 998 (niu_hsvc->hsvc_major == 1 && 999 niu_hsvc->hsvc_minor == 1)) { 1000 nxge->environs = SOLARIS_SERVICE_DOMAIN; 1001 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 1002 "nxge_hio_init: hypervisor services " 1003 "version %d.%d", 1004 niu_hsvc->hsvc_major, 1005 niu_hsvc->hsvc_minor)); 1006 } 1007 } 1008 } 1009 1010 /* 1011 * Initialize share and ring group structures. 1012 */ 1013 for (i = 0; i < NXGE_MAX_TDC_GROUPS; i++) { 1014 nxge->tx_hio_groups[i].ghandle = NULL; 1015 nxge->tx_hio_groups[i].nxgep = nxge; 1016 nxge->tx_hio_groups[i].type = MAC_RING_TYPE_TX; 1017 nxge->tx_hio_groups[i].gindex = 0; 1018 nxge->tx_hio_groups[i].sindex = 0; 1019 } 1020 1021 for (i = 0; i < NXGE_MAX_RDC_GROUPS; i++) { 1022 nxge->rx_hio_groups[i].ghandle = NULL; 1023 nxge->rx_hio_groups[i].nxgep = nxge; 1024 nxge->rx_hio_groups[i].type = MAC_RING_TYPE_RX; 1025 nxge->rx_hio_groups[i].gindex = 0; 1026 nxge->rx_hio_groups[i].sindex = 0; 1027 nxge->rx_hio_groups[i].started = B_FALSE; 1028 nxge->rx_hio_groups[i].port_default_grp = B_FALSE; 1029 nxge->rx_hio_groups[i].rdctbl = -1; 1030 nxge->rx_hio_groups[i].n_mac_addrs = 0; 1031 } 1032 1033 if (!isLDOMs(nxge)) { 1034 nhd->hio.ldoms = B_FALSE; 1035 return (NXGE_OK); 1036 } 1037 1038 nhd->hio.ldoms = B_TRUE; 1039 1040 /* 1041 * Fill in what we can. 1042 */ 1043 for (region = 0; region < NXGE_VR_SR_MAX; region++) { 1044 nhd->vr[region].region = region; 1045 } 1046 nhd->vrs = NXGE_VR_SR_MAX - 2; 1047 1048 /* 1049 * Initialize the share stuctures. 1050 */ 1051 for (i = 0; i < NXGE_MAX_TDCS; i++) 1052 nxge->tdc_is_shared[i] = B_FALSE; 1053 1054 for (i = 0; i < NXGE_VR_SR_MAX; i++) { 1055 nxge->shares[i].nxgep = nxge; 1056 nxge->shares[i].index = 0; 1057 nxge->shares[i].vrp = NULL; 1058 nxge->shares[i].tmap = 0; 1059 nxge->shares[i].rmap = 0; 1060 nxge->shares[i].rxgroup = 0; 1061 nxge->shares[i].active = B_FALSE; 1062 } 1063 1064 /* Fill in the HV HIO function pointers. */ 1065 nxge_hio_hv_init(nxge); 1066 1067 if (isLDOMservice(nxge)) { 1068 NXGE_DEBUG_MSG((nxge, HIO_CTL, 1069 "Hybrid IO-capable service domain")); 1070 return (NXGE_OK); 1071 } 1072 1073 return (0); 1074 } 1075 #endif /* defined(sun4v) */ 1076 1077 static int 1078 nxge_hio_group_mac_add(nxge_t *nxge, nxge_ring_group_t *g, 1079 const uint8_t *macaddr) 1080 { 1081 int rv; 1082 nxge_rdc_grp_t *group; 1083 1084 mutex_enter(nxge->genlock); 1085 1086 /* 1087 * Initialize the NXGE RDC table data structure. 1088 */ 1089 group = &nxge->pt_config.rdc_grps[g->rdctbl]; 1090 if (!group->flag) { 1091 group->port = NXGE_GET_PORT_NUM(nxge->function_num); 1092 group->config_method = RDC_TABLE_ENTRY_METHOD_REP; 1093 group->flag = B_TRUE; /* This group has been configured. */ 1094 } 1095 1096 mutex_exit(nxge->genlock); 1097 1098 /* 1099 * Add the MAC address. 1100 */ 1101 if ((rv = nxge_m_mmac_add_g((void *)nxge, macaddr, 1102 g->rdctbl, B_TRUE)) != 0) { 1103 return (rv); 1104 } 1105 1106 mutex_enter(nxge->genlock); 1107 g->n_mac_addrs++; 1108 mutex_exit(nxge->genlock); 1109 return (0); 1110 } 1111 1112 static int 1113 nxge_hio_set_unicst(void *arg, const uint8_t *macaddr) 1114 { 1115 p_nxge_t nxgep = (p_nxge_t)arg; 1116 struct ether_addr addrp; 1117 1118 bcopy(macaddr, (uint8_t *)&addrp, ETHERADDRL); 1119 if (nxge_set_mac_addr(nxgep, &addrp)) { 1120 NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, 1121 "<== nxge_m_unicst: set unitcast failed")); 1122 return (EINVAL); 1123 } 1124 1125 nxgep->primary = B_TRUE; 1126 1127 return (0); 1128 } 1129 1130 /*ARGSUSED*/ 1131 static int 1132 nxge_hio_clear_unicst(p_nxge_t nxgep, const uint8_t *mac_addr) 1133 { 1134 nxgep->primary = B_FALSE; 1135 return (0); 1136 } 1137 1138 static int 1139 nxge_hio_add_mac(void *arg, const uint8_t *mac_addr) 1140 { 1141 nxge_ring_group_t *group = (nxge_ring_group_t *)arg; 1142 p_nxge_t nxge = group->nxgep; 1143 int rv; 1144 nxge_hio_vr_t *vr; /* The Virtualization Region */ 1145 1146 ASSERT(group->type == MAC_RING_TYPE_RX); 1147 ASSERT(group->nxgep != NULL); 1148 1149 if (isLDOMguest(group->nxgep)) 1150 return (0); 1151 1152 mutex_enter(nxge->genlock); 1153 1154 if (!nxge->primary && group->port_default_grp) { 1155 rv = nxge_hio_set_unicst((void *)nxge, mac_addr); 1156 mutex_exit(nxge->genlock); 1157 return (rv); 1158 } 1159 1160 /* 1161 * If the group is associated with a VR, then only one 1162 * address may be assigned to the group. 1163 */ 1164 vr = (nxge_hio_vr_t *)nxge->shares[group->sindex].vrp; 1165 if ((vr != NULL) && (group->n_mac_addrs)) { 1166 mutex_exit(nxge->genlock); 1167 return (ENOSPC); 1168 } 1169 1170 mutex_exit(nxge->genlock); 1171 1172 /* 1173 * Program the mac address for the group. 1174 */ 1175 if ((rv = nxge_hio_group_mac_add(nxge, group, mac_addr)) != 0) { 1176 return (rv); 1177 } 1178 1179 return (0); 1180 } 1181 1182 static int 1183 find_mac_slot(nxge_mmac_t *mmac_info, const uint8_t *mac_addr) 1184 { 1185 int i; 1186 for (i = 0; i <= mmac_info->num_mmac; i++) { 1187 if (memcmp(mmac_info->mac_pool[i].addr, mac_addr, 1188 ETHERADDRL) == 0) { 1189 return (i); 1190 } 1191 } 1192 return (-1); 1193 } 1194 1195 /* ARGSUSED */ 1196 static int 1197 nxge_hio_rem_mac(void *arg, const uint8_t *mac_addr) 1198 { 1199 nxge_ring_group_t *group = (nxge_ring_group_t *)arg; 1200 struct ether_addr addrp; 1201 p_nxge_t nxge = group->nxgep; 1202 nxge_mmac_t *mmac_info; 1203 int rv, slot; 1204 1205 ASSERT(group->type == MAC_RING_TYPE_RX); 1206 ASSERT(group->nxgep != NULL); 1207 1208 if (isLDOMguest(group->nxgep)) 1209 return (0); 1210 1211 mutex_enter(nxge->genlock); 1212 1213 mmac_info = &nxge->nxge_mmac_info; 1214 slot = find_mac_slot(mmac_info, mac_addr); 1215 if (slot < 0) { 1216 if (group->port_default_grp && nxge->primary) { 1217 bcopy(mac_addr, (uint8_t *)&addrp, ETHERADDRL); 1218 if (ether_cmp(&addrp, &nxge->ouraddr) == 0) { 1219 rv = nxge_hio_clear_unicst(nxge, mac_addr); 1220 mutex_exit(nxge->genlock); 1221 return (rv); 1222 } else { 1223 mutex_exit(nxge->genlock); 1224 return (EINVAL); 1225 } 1226 } else { 1227 mutex_exit(nxge->genlock); 1228 return (EINVAL); 1229 } 1230 } 1231 1232 mutex_exit(nxge->genlock); 1233 1234 /* 1235 * Remove the mac address for the group 1236 */ 1237 if ((rv = nxge_m_mmac_remove(nxge, slot)) != 0) { 1238 return (rv); 1239 } 1240 1241 mutex_enter(nxge->genlock); 1242 group->n_mac_addrs--; 1243 mutex_exit(nxge->genlock); 1244 1245 return (0); 1246 } 1247 1248 static int 1249 nxge_hio_group_start(mac_group_driver_t gdriver) 1250 { 1251 nxge_ring_group_t *group = (nxge_ring_group_t *)gdriver; 1252 nxge_rdc_grp_t *rdc_grp_p; 1253 int rdctbl; 1254 int dev_gindex; 1255 1256 ASSERT(group->type == MAC_RING_TYPE_RX); 1257 ASSERT(group->nxgep != NULL); 1258 1259 ASSERT(group->nxgep->nxge_mac_state == NXGE_MAC_STARTED); 1260 if (group->nxgep->nxge_mac_state != NXGE_MAC_STARTED) 1261 return (ENXIO); 1262 1263 mutex_enter(group->nxgep->genlock); 1264 if (isLDOMguest(group->nxgep)) 1265 goto nxge_hio_group_start_exit; 1266 1267 dev_gindex = group->nxgep->pt_config.hw_config.def_mac_rxdma_grpid + 1268 group->gindex; 1269 rdc_grp_p = &group->nxgep->pt_config.rdc_grps[dev_gindex]; 1270 1271 /* 1272 * Get an rdc table for this group. 1273 * Group ID is given by the caller, and that's the group it needs 1274 * to bind to. The default group is already bound when the driver 1275 * was attached. 1276 * 1277 * For Group 0, it's RDC table was allocated at attach time 1278 * no need to allocate a new table. 1279 */ 1280 if (group->gindex != 0) { 1281 rdctbl = nxge_fzc_rdc_tbl_bind(group->nxgep, 1282 dev_gindex, B_TRUE); 1283 if (rdctbl < 0) { 1284 mutex_exit(group->nxgep->genlock); 1285 return (rdctbl); 1286 } 1287 } else { 1288 rdctbl = group->nxgep->pt_config.hw_config.def_mac_rxdma_grpid; 1289 } 1290 1291 group->rdctbl = rdctbl; 1292 1293 (void) nxge_init_fzc_rdc_tbl(group->nxgep, rdc_grp_p, rdctbl); 1294 1295 nxge_hio_group_start_exit: 1296 group->started = B_TRUE; 1297 mutex_exit(group->nxgep->genlock); 1298 return (0); 1299 } 1300 1301 static void 1302 nxge_hio_group_stop(mac_group_driver_t gdriver) 1303 { 1304 nxge_ring_group_t *group = (nxge_ring_group_t *)gdriver; 1305 1306 ASSERT(group->type == MAC_RING_TYPE_RX); 1307 1308 mutex_enter(group->nxgep->genlock); 1309 group->started = B_FALSE; 1310 1311 if (isLDOMguest(group->nxgep)) 1312 goto nxge_hio_group_stop_exit; 1313 1314 /* 1315 * Unbind the RDC table previously bound for this group. 1316 * 1317 * Since RDC table for group 0 was allocated at attach 1318 * time, no need to unbind the table here. 1319 */ 1320 if (group->gindex != 0) 1321 (void) nxge_fzc_rdc_tbl_unbind(group->nxgep, group->rdctbl); 1322 1323 nxge_hio_group_stop_exit: 1324 mutex_exit(group->nxgep->genlock); 1325 } 1326 1327 /* ARGSUSED */ 1328 void 1329 nxge_hio_group_get(void *arg, mac_ring_type_t type, int groupid, 1330 mac_group_info_t *infop, mac_group_handle_t ghdl) 1331 { 1332 p_nxge_t nxgep = (p_nxge_t)arg; 1333 nxge_ring_group_t *group; 1334 int dev_gindex; 1335 1336 switch (type) { 1337 case MAC_RING_TYPE_RX: 1338 group = &nxgep->rx_hio_groups[groupid]; 1339 group->nxgep = nxgep; 1340 group->ghandle = ghdl; 1341 group->gindex = groupid; 1342 group->sindex = 0; /* not yet bound to a share */ 1343 1344 if (!isLDOMguest(nxgep)) { 1345 dev_gindex = 1346 nxgep->pt_config.hw_config.def_mac_rxdma_grpid + 1347 groupid; 1348 1349 if (nxgep->pt_config.hw_config.def_mac_rxdma_grpid == 1350 dev_gindex) 1351 group->port_default_grp = B_TRUE; 1352 1353 infop->mgi_count = 1354 nxgep->pt_config.rdc_grps[dev_gindex].max_rdcs; 1355 } else { 1356 infop->mgi_count = NXGE_HIO_SHARE_MAX_CHANNELS; 1357 } 1358 1359 infop->mgi_driver = (mac_group_driver_t)group; 1360 infop->mgi_start = nxge_hio_group_start; 1361 infop->mgi_stop = nxge_hio_group_stop; 1362 infop->mgi_addmac = nxge_hio_add_mac; 1363 infop->mgi_remmac = nxge_hio_rem_mac; 1364 break; 1365 1366 case MAC_RING_TYPE_TX: 1367 /* 1368 * 'groupid' for TX should be incremented by one since 1369 * the default group (groupid 0) is not known by the MAC layer 1370 */ 1371 group = &nxgep->tx_hio_groups[groupid + 1]; 1372 group->nxgep = nxgep; 1373 group->ghandle = ghdl; 1374 group->gindex = groupid + 1; 1375 group->sindex = 0; /* not yet bound to a share */ 1376 1377 infop->mgi_driver = (mac_group_driver_t)group; 1378 infop->mgi_start = NULL; 1379 infop->mgi_stop = NULL; 1380 infop->mgi_addmac = NULL; /* not needed */ 1381 infop->mgi_remmac = NULL; /* not needed */ 1382 /* no rings associated with group initially */ 1383 infop->mgi_count = 0; 1384 break; 1385 } 1386 } 1387 1388 #if defined(sun4v) 1389 1390 int 1391 nxge_hio_share_assign( 1392 nxge_t *nxge, 1393 uint64_t cookie, 1394 res_map_t *tmap, 1395 res_map_t *rmap, 1396 nxge_hio_vr_t *vr) 1397 { 1398 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 1399 uint64_t slot, hv_rv; 1400 nxge_hio_dc_t *dc; 1401 nxhv_vr_fp_t *fp; 1402 int i; 1403 uint64_t major; 1404 1405 /* 1406 * Ask the Hypervisor to set up the VR for us 1407 */ 1408 fp = &nhd->hio.vr; 1409 major = nxge->niu_hsvc.hsvc_major; 1410 switch (major) { 1411 case NIU_MAJOR_VER: /* 1 */ 1412 if ((hv_rv = (*fp->assign)(vr->region, cookie, &vr->cookie))) { 1413 NXGE_ERROR_MSG((nxge, HIO_CTL, 1414 "nxge_hio_share_assign: major %d " 1415 "vr->assign() returned %d", major, hv_rv)); 1416 nxge_hio_unshare(vr); 1417 return (-EIO); 1418 } 1419 1420 break; 1421 1422 case NIU_MAJOR_VER_2: /* 2 */ 1423 default: 1424 if ((hv_rv = (*fp->cfgh_assign) 1425 (nxge->niu_cfg_hdl, vr->region, cookie, &vr->cookie))) { 1426 NXGE_ERROR_MSG((nxge, HIO_CTL, 1427 "nxge_hio_share_assign: major %d " 1428 "vr->assign() returned %d", major, hv_rv)); 1429 nxge_hio_unshare(vr); 1430 return (-EIO); 1431 } 1432 1433 break; 1434 } 1435 1436 NXGE_DEBUG_MSG((nxge, HIO_CTL, 1437 "nxge_hio_share_assign: major %d " 1438 "vr->assign() success", major)); 1439 1440 /* 1441 * For each shared TDC, ask the HV to find us an empty slot. 1442 */ 1443 dc = vr->tx_group.dc; 1444 for (i = 0; i < NXGE_MAX_TDCS; i++) { 1445 nxhv_dc_fp_t *tx = &nhd->hio.tx; 1446 while (dc) { 1447 hv_rv = (*tx->assign) 1448 (vr->cookie, dc->channel, &slot); 1449 if (hv_rv != 0) { 1450 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 1451 "nxge_hio_share_assign: " 1452 "tx->assign(%x, %d) failed: %ld", 1453 vr->cookie, dc->channel, hv_rv)); 1454 return (-EIO); 1455 } 1456 1457 dc->cookie = vr->cookie; 1458 dc->page = (vp_channel_t)slot; 1459 1460 /* Inform the caller about the slot chosen. */ 1461 (*tmap) |= 1 << slot; 1462 1463 dc = dc->next; 1464 } 1465 } 1466 1467 /* 1468 * For each shared RDC, ask the HV to find us an empty slot. 1469 */ 1470 dc = vr->rx_group.dc; 1471 for (i = 0; i < NXGE_MAX_RDCS; i++) { 1472 nxhv_dc_fp_t *rx = &nhd->hio.rx; 1473 while (dc) { 1474 hv_rv = (*rx->assign) 1475 (vr->cookie, dc->channel, &slot); 1476 if (hv_rv != 0) { 1477 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 1478 "nxge_hio_share_assign: " 1479 "rx->assign(%x, %d) failed: %ld", 1480 vr->cookie, dc->channel, hv_rv)); 1481 return (-EIO); 1482 } 1483 1484 dc->cookie = vr->cookie; 1485 dc->page = (vp_channel_t)slot; 1486 1487 /* Inform the caller about the slot chosen. */ 1488 (*rmap) |= 1 << slot; 1489 1490 dc = dc->next; 1491 } 1492 } 1493 1494 return (0); 1495 } 1496 1497 void 1498 nxge_hio_share_unassign( 1499 nxge_hio_vr_t *vr) 1500 { 1501 nxge_t *nxge = (nxge_t *)vr->nxge; 1502 nxge_hio_data_t *nhd; 1503 nxge_hio_dc_t *dc; 1504 nxhv_vr_fp_t *fp; 1505 uint64_t hv_rv; 1506 1507 nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 1508 1509 dc = vr->tx_group.dc; 1510 while (dc) { 1511 nxhv_dc_fp_t *tx = &nhd->hio.tx; 1512 hv_rv = (*tx->unassign)(vr->cookie, dc->page); 1513 if (hv_rv != 0) { 1514 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 1515 "nxge_hio_share_unassign: " 1516 "tx->unassign(%x, %d) failed: %ld", 1517 vr->cookie, dc->page, hv_rv)); 1518 } 1519 dc = dc->next; 1520 } 1521 1522 dc = vr->rx_group.dc; 1523 while (dc) { 1524 nxhv_dc_fp_t *rx = &nhd->hio.rx; 1525 hv_rv = (*rx->unassign)(vr->cookie, dc->page); 1526 if (hv_rv != 0) { 1527 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 1528 "nxge_hio_share_unassign: " 1529 "rx->unassign(%x, %d) failed: %ld", 1530 vr->cookie, dc->page, hv_rv)); 1531 } 1532 dc = dc->next; 1533 } 1534 1535 fp = &nhd->hio.vr; 1536 if (fp->unassign) { 1537 hv_rv = (*fp->unassign)(vr->cookie); 1538 if (hv_rv != 0) { 1539 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 1540 "nxge_hio_share_unassign: " 1541 "vr->assign(%x) failed: %ld", 1542 vr->cookie, hv_rv)); 1543 } 1544 } 1545 } 1546 1547 int 1548 nxge_hio_share_alloc(void *arg, mac_share_handle_t *shandle) 1549 { 1550 p_nxge_t nxge = (p_nxge_t)arg; 1551 nxge_share_handle_t *shp; 1552 nxge_hio_vr_t *vr; /* The Virtualization Region */ 1553 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 1554 1555 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_share")); 1556 1557 if (nhd->hio.vr.assign == 0 || nhd->hio.tx.assign == 0 || 1558 nhd->hio.rx.assign == 0) { 1559 NXGE_ERROR_MSG((nxge, HIO_CTL, "HV assign function(s) NULL")); 1560 return (EIO); 1561 } 1562 1563 /* 1564 * Get a VR. 1565 */ 1566 if ((vr = nxge_hio_vr_share(nxge)) == 0) 1567 return (EAGAIN); 1568 1569 shp = &nxge->shares[vr->region]; 1570 shp->nxgep = nxge; 1571 shp->index = vr->region; 1572 shp->vrp = (void *)vr; 1573 shp->tmap = shp->rmap = 0; /* to be assigned by ms_sbind */ 1574 shp->rxgroup = 0; /* to be assigned by ms_sadd */ 1575 shp->active = B_FALSE; /* not bound yet */ 1576 1577 *shandle = (mac_share_handle_t)shp; 1578 1579 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_share")); 1580 return (0); 1581 } 1582 1583 1584 void 1585 nxge_hio_share_free(mac_share_handle_t shandle) 1586 { 1587 nxge_share_handle_t *shp = (nxge_share_handle_t *)shandle; 1588 nxge_hio_vr_t *vr; 1589 1590 /* 1591 * Clear internal handle state. 1592 */ 1593 vr = shp->vrp; 1594 shp->vrp = (void *)NULL; 1595 shp->index = 0; 1596 shp->tmap = 0; 1597 shp->rmap = 0; 1598 shp->rxgroup = 0; 1599 shp->active = B_FALSE; 1600 1601 /* 1602 * Free VR resource. 1603 */ 1604 nxge_hio_unshare(vr); 1605 } 1606 1607 1608 void 1609 nxge_hio_share_query(mac_share_handle_t shandle, mac_ring_type_t type, 1610 mac_ring_handle_t *rings, uint_t *n_rings) 1611 { 1612 nxge_t *nxge; 1613 nxge_share_handle_t *shp = (nxge_share_handle_t *)shandle; 1614 nxge_ring_handle_t *rh; 1615 uint32_t offset; 1616 1617 nxge = shp->nxgep; 1618 1619 switch (type) { 1620 case MAC_RING_TYPE_RX: 1621 rh = nxge->rx_ring_handles; 1622 offset = nxge->pt_config.hw_config.start_rdc; 1623 break; 1624 1625 case MAC_RING_TYPE_TX: 1626 rh = nxge->tx_ring_handles; 1627 offset = nxge->pt_config.hw_config.tdc.start; 1628 break; 1629 } 1630 1631 /* 1632 * In version 1.0, we may only give a VR 2 RDCs/TDCs. Not only that, 1633 * but the HV has statically assigned the channels like so: 1634 * VR0: RDC0 & RDC1 1635 * VR1: RDC2 & RDC3, etc. 1636 * The TDCs are assigned in exactly the same way. 1637 */ 1638 if (rings != NULL) { 1639 rings[0] = rh[(shp->index * 2) - offset].ring_handle; 1640 rings[1] = rh[(shp->index * 2 + 1) - offset].ring_handle; 1641 } 1642 if (n_rings != NULL) { 1643 *n_rings = 2; 1644 } 1645 } 1646 1647 int 1648 nxge_hio_share_add_group(mac_share_handle_t shandle, 1649 mac_group_driver_t ghandle) 1650 { 1651 nxge_t *nxge; 1652 nxge_share_handle_t *shp = (nxge_share_handle_t *)shandle; 1653 nxge_ring_group_t *rg = (nxge_ring_group_t *)ghandle; 1654 nxge_hio_vr_t *vr; /* The Virtualization Region */ 1655 nxge_grp_t *group; 1656 int i; 1657 1658 if (rg->sindex != 0) { 1659 /* the group is already bound to a share */ 1660 return (EALREADY); 1661 } 1662 1663 /* 1664 * If we are adding a group 0 to a share, this 1665 * is not correct. 1666 */ 1667 ASSERT(rg->gindex != 0); 1668 1669 nxge = rg->nxgep; 1670 vr = shp->vrp; 1671 1672 switch (rg->type) { 1673 case MAC_RING_TYPE_RX: 1674 /* 1675 * Make sure that the group has the right rings associated 1676 * for the share. In version 1.0, we may only give a VR 1677 * 2 RDCs. Not only that, but the HV has statically 1678 * assigned the channels like so: 1679 * VR0: RDC0 & RDC1 1680 * VR1: RDC2 & RDC3, etc. 1681 */ 1682 group = nxge->rx_set.group[rg->gindex]; 1683 1684 if (group->count > 2) { 1685 /* a share can have at most 2 rings */ 1686 return (EINVAL); 1687 } 1688 1689 for (i = 0; i < NXGE_MAX_RDCS; i++) { 1690 if (group->map & (1 << i)) { 1691 if ((i != shp->index * 2) && 1692 (i != (shp->index * 2 + 1))) { 1693 /* 1694 * A group with invalid rings was 1695 * attempted to bind to this share 1696 */ 1697 return (EINVAL); 1698 } 1699 } 1700 } 1701 1702 rg->sindex = vr->region; 1703 vr->rdc_tbl = rg->rdctbl; 1704 shp->rxgroup = vr->rdc_tbl; 1705 break; 1706 1707 case MAC_RING_TYPE_TX: 1708 /* 1709 * Make sure that the group has the right rings associated 1710 * for the share. In version 1.0, we may only give a VR 1711 * 2 TDCs. Not only that, but the HV has statically 1712 * assigned the channels like so: 1713 * VR0: TDC0 & TDC1 1714 * VR1: TDC2 & TDC3, etc. 1715 */ 1716 group = nxge->tx_set.group[rg->gindex]; 1717 1718 if (group->count > 2) { 1719 /* a share can have at most 2 rings */ 1720 return (EINVAL); 1721 } 1722 1723 for (i = 0; i < NXGE_MAX_TDCS; i++) { 1724 if (group->map & (1 << i)) { 1725 if ((i != shp->index * 2) && 1726 (i != (shp->index * 2 + 1))) { 1727 /* 1728 * A group with invalid rings was 1729 * attempted to bind to this share 1730 */ 1731 return (EINVAL); 1732 } 1733 } 1734 } 1735 1736 vr->tdc_tbl = nxge->pt_config.hw_config.def_mac_txdma_grpid + 1737 rg->gindex; 1738 rg->sindex = vr->region; 1739 break; 1740 } 1741 return (0); 1742 } 1743 1744 int 1745 nxge_hio_share_rem_group(mac_share_handle_t shandle, 1746 mac_group_driver_t ghandle) 1747 { 1748 nxge_share_handle_t *shp = (nxge_share_handle_t *)shandle; 1749 nxge_ring_group_t *group = (nxge_ring_group_t *)ghandle; 1750 nxge_hio_vr_t *vr; /* The Virtualization Region */ 1751 int rv = 0; 1752 1753 vr = shp->vrp; 1754 1755 switch (group->type) { 1756 case MAC_RING_TYPE_RX: 1757 group->sindex = 0; 1758 vr->rdc_tbl = 0; 1759 shp->rxgroup = 0; 1760 break; 1761 1762 case MAC_RING_TYPE_TX: 1763 group->sindex = 0; 1764 vr->tdc_tbl = 0; 1765 break; 1766 } 1767 1768 return (rv); 1769 } 1770 1771 int 1772 nxge_hio_share_bind(mac_share_handle_t shandle, uint64_t cookie, 1773 uint64_t *rcookie) 1774 { 1775 nxge_t *nxge; 1776 nxge_share_handle_t *shp = (nxge_share_handle_t *)shandle; 1777 nxge_hio_vr_t *vr; 1778 uint64_t rmap, tmap, hv_rmap, hv_tmap; 1779 int rv; 1780 1781 nxge = shp->nxgep; 1782 vr = (nxge_hio_vr_t *)shp->vrp; 1783 1784 /* 1785 * Add resources to the share. 1786 * For each DMA channel associated with the VR, bind its resources 1787 * to the VR. 1788 */ 1789 tmap = 0; 1790 rv = nxge_hio_addres(vr, MAC_RING_TYPE_TX, &tmap); 1791 if (rv != 0) { 1792 return (rv); 1793 } 1794 1795 rmap = 0; 1796 rv = nxge_hio_addres(vr, MAC_RING_TYPE_RX, &rmap); 1797 if (rv != 0) { 1798 nxge_hio_remres(vr, MAC_RING_TYPE_TX, tmap); 1799 return (rv); 1800 } 1801 1802 /* 1803 * Ask the Hypervisor to set up the VR and allocate slots for 1804 * each rings associated with the VR. 1805 */ 1806 hv_tmap = hv_rmap = 0; 1807 if ((rv = nxge_hio_share_assign(nxge, cookie, 1808 &hv_tmap, &hv_rmap, vr))) { 1809 nxge_hio_remres(vr, MAC_RING_TYPE_TX, tmap); 1810 nxge_hio_remres(vr, MAC_RING_TYPE_RX, rmap); 1811 return (rv); 1812 } 1813 1814 shp->active = B_TRUE; 1815 shp->tmap = hv_tmap; 1816 shp->rmap = hv_rmap; 1817 1818 /* high 32 bits are cfg_hdl and low 32 bits are HV cookie */ 1819 *rcookie = (((uint64_t)nxge->niu_cfg_hdl) << 32) | vr->cookie; 1820 1821 return (0); 1822 } 1823 1824 void 1825 nxge_hio_share_unbind(mac_share_handle_t shandle) 1826 { 1827 nxge_share_handle_t *shp = (nxge_share_handle_t *)shandle; 1828 1829 /* 1830 * First, unassign the VR (take it back), 1831 * so we can enable interrupts again. 1832 */ 1833 nxge_hio_share_unassign(shp->vrp); 1834 1835 /* 1836 * Free Ring Resources for TX and RX 1837 */ 1838 nxge_hio_remres(shp->vrp, MAC_RING_TYPE_TX, shp->tmap); 1839 nxge_hio_remres(shp->vrp, MAC_RING_TYPE_RX, shp->rmap); 1840 } 1841 1842 1843 /* 1844 * nxge_hio_vr_share 1845 * 1846 * Find an unused Virtualization Region (VR). 1847 * 1848 * Arguments: 1849 * nxge 1850 * 1851 * Notes: 1852 * 1853 * Context: 1854 * Service domain 1855 */ 1856 nxge_hio_vr_t * 1857 nxge_hio_vr_share( 1858 nxge_t *nxge) 1859 { 1860 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 1861 nxge_hio_vr_t *vr; 1862 1863 int first, limit, region; 1864 1865 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_vr_share")); 1866 1867 MUTEX_ENTER(&nhd->lock); 1868 1869 if (nhd->vrs == 0) { 1870 MUTEX_EXIT(&nhd->lock); 1871 return (0); 1872 } 1873 1874 /* Find an empty virtual region (VR). */ 1875 if (nxge->function_num == 0) { 1876 // FUNC0_VIR0 'belongs' to NIU port 0. 1877 first = FUNC0_VIR1; 1878 limit = FUNC2_VIR0; 1879 } else if (nxge->function_num == 1) { 1880 // FUNC2_VIR0 'belongs' to NIU port 1. 1881 first = FUNC2_VIR1; 1882 limit = FUNC_VIR_MAX; 1883 } else { 1884 cmn_err(CE_WARN, 1885 "Shares not supported on function(%d) at this time.\n", 1886 nxge->function_num); 1887 } 1888 1889 for (region = first; region < limit; region++) { 1890 if (nhd->vr[region].nxge == 0) 1891 break; 1892 } 1893 1894 if (region == limit) { 1895 MUTEX_EXIT(&nhd->lock); 1896 return (0); 1897 } 1898 1899 vr = &nhd->vr[region]; 1900 vr->nxge = (uintptr_t)nxge; 1901 vr->region = (uintptr_t)region; 1902 1903 nhd->vrs--; 1904 1905 MUTEX_EXIT(&nhd->lock); 1906 1907 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_vr_share")); 1908 1909 return (vr); 1910 } 1911 1912 void 1913 nxge_hio_unshare( 1914 nxge_hio_vr_t *vr) 1915 { 1916 nxge_t *nxge = (nxge_t *)vr->nxge; 1917 nxge_hio_data_t *nhd; 1918 1919 vr_region_t region; 1920 1921 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_unshare")); 1922 1923 if (!nxge) { 1924 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_unshare: " 1925 "vr->nxge is NULL")); 1926 return; 1927 } 1928 1929 /* 1930 * This function is no longer called, but I will keep it 1931 * here in case we want to revisit this topic in the future. 1932 * 1933 * nxge_hio_hostinfo_uninit(nxge, vr); 1934 */ 1935 1936 /* 1937 * XXX: This is done by ms_sremove? 1938 * (void) nxge_fzc_rdc_tbl_unbind(nxge, vr->rdc_tbl); 1939 */ 1940 1941 nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 1942 1943 MUTEX_ENTER(&nhd->lock); 1944 1945 region = vr->region; 1946 (void) memset(vr, 0, sizeof (*vr)); 1947 vr->region = region; 1948 1949 nhd->vrs++; 1950 1951 MUTEX_EXIT(&nhd->lock); 1952 1953 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_unshare")); 1954 } 1955 1956 int 1957 nxge_hio_addres(nxge_hio_vr_t *vr, mac_ring_type_t type, uint64_t *map) 1958 { 1959 nxge_t *nxge = (nxge_t *)vr->nxge; 1960 nxge_grp_t *group; 1961 int groupid; 1962 int i, rv = 0; 1963 int max_dcs; 1964 1965 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_addres")); 1966 1967 if (!nxge) 1968 return (EINVAL); 1969 1970 /* 1971 * For each ring associated with the group, add the resources 1972 * to the group and bind. 1973 */ 1974 max_dcs = (type == MAC_RING_TYPE_TX) ? NXGE_MAX_TDCS : NXGE_MAX_RDCS; 1975 if (type == MAC_RING_TYPE_TX) { 1976 /* set->group is an array of group indexed by a port group id */ 1977 groupid = vr->tdc_tbl - 1978 nxge->pt_config.hw_config.def_mac_txdma_grpid; 1979 group = nxge->tx_set.group[groupid]; 1980 } else { 1981 /* set->group is an array of group indexed by a port group id */ 1982 groupid = vr->rdc_tbl - 1983 nxge->pt_config.hw_config.def_mac_rxdma_grpid; 1984 group = nxge->rx_set.group[groupid]; 1985 } 1986 1987 if (group->map == 0) { 1988 NXGE_DEBUG_MSG((nxge, HIO_CTL, "There is no rings associated " 1989 "with this VR")); 1990 return (EINVAL); 1991 } 1992 1993 for (i = 0; i < max_dcs; i++) { 1994 if (group->map & (1 << i)) { 1995 if ((rv = nxge_hio_dc_share(nxge, vr, type, i)) < 0) { 1996 if (*map == 0) /* Couldn't get even one DC. */ 1997 return (-rv); 1998 else 1999 break; 2000 } 2001 *map |= (1 << i); 2002 } 2003 } 2004 2005 if ((*map == 0) || (rv != 0)) { 2006 NXGE_DEBUG_MSG((nxge, HIO_CTL, 2007 "<== nxge_hio_addres: rv(%x)", rv)); 2008 return (EIO); 2009 } 2010 2011 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_addres")); 2012 return (0); 2013 } 2014 2015 /* ARGSUSED */ 2016 void 2017 nxge_hio_remres( 2018 nxge_hio_vr_t *vr, 2019 mac_ring_type_t type, 2020 res_map_t res_map) 2021 { 2022 nxge_t *nxge = (nxge_t *)vr->nxge; 2023 nxge_grp_t *group; 2024 2025 if (!nxge) { 2026 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_remres: " 2027 "vr->nxge is NULL")); 2028 return; 2029 } 2030 2031 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_remres(%lx)", res_map)); 2032 2033 /* 2034 * For each ring bound to the group, remove the DMA resources 2035 * from the group and unbind. 2036 */ 2037 group = (type == MAC_RING_TYPE_TX ? &vr->tx_group : &vr->rx_group); 2038 while (group->dc) { 2039 nxge_hio_dc_t *dc = group->dc; 2040 NXGE_DC_RESET(res_map, dc->page); 2041 nxge_hio_dc_unshare(nxge, vr, type, dc->channel); 2042 } 2043 2044 if (res_map) { 2045 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_remres: " 2046 "res_map %lx", res_map)); 2047 } 2048 2049 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_remres")); 2050 } 2051 2052 /* 2053 * nxge_hio_tdc_share 2054 * 2055 * Share an unused TDC channel. 2056 * 2057 * Arguments: 2058 * nxge 2059 * 2060 * Notes: 2061 * 2062 * A.7.3 Reconfigure Tx DMA channel 2063 * Disable TxDMA A.9.6.10 2064 * [Rebind TxDMA channel to Port A.9.6.7] 2065 * 2066 * We don't have to Rebind the TDC to the port - it always already bound. 2067 * 2068 * Soft Reset TxDMA A.9.6.2 2069 * 2070 * This procedure will be executed by nxge_init_txdma_channel() in the 2071 * guest domain: 2072 * 2073 * Re-initialize TxDMA A.9.6.8 2074 * Reconfigure TxDMA 2075 * Enable TxDMA A.9.6.9 2076 * 2077 * Context: 2078 * Service domain 2079 */ 2080 int 2081 nxge_hio_tdc_share( 2082 nxge_t *nxge, 2083 int channel) 2084 { 2085 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 2086 nxge_grp_set_t *set = &nxge->tx_set; 2087 tx_ring_t *ring; 2088 int count; 2089 2090 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_tdc_share")); 2091 2092 /* 2093 * Wait until this channel is idle. 2094 */ 2095 ring = nxge->tx_rings->rings[channel]; 2096 ASSERT(ring != NULL); 2097 2098 (void) atomic_swap_32(&ring->tx_ring_offline, NXGE_TX_RING_OFFLINING); 2099 if (ring->tx_ring_busy) { 2100 /* 2101 * Wait for 30 seconds. 2102 */ 2103 for (count = 30 * 1000; count; count--) { 2104 if (ring->tx_ring_offline & NXGE_TX_RING_OFFLINED) { 2105 break; 2106 } 2107 2108 drv_usecwait(1000); 2109 } 2110 2111 if (count == 0) { 2112 (void) atomic_swap_32(&ring->tx_ring_offline, 2113 NXGE_TX_RING_ONLINE); 2114 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 2115 "nxge_hio_tdc_share: " 2116 "Tx ring %d was always BUSY", channel)); 2117 return (-EIO); 2118 } 2119 } else { 2120 (void) atomic_swap_32(&ring->tx_ring_offline, 2121 NXGE_TX_RING_OFFLINED); 2122 } 2123 2124 MUTEX_ENTER(&nhd->lock); 2125 nxge->tdc_is_shared[channel] = B_TRUE; 2126 MUTEX_EXIT(&nhd->lock); 2127 2128 if (nxge_intr_remove(nxge, VP_BOUND_TX, channel) != NXGE_OK) { 2129 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_tdc_share: " 2130 "Failed to remove interrupt for TxDMA channel %d", 2131 channel)); 2132 return (-EINVAL); 2133 } 2134 2135 /* Disable TxDMA A.9.6.10 */ 2136 (void) nxge_txdma_channel_disable(nxge, channel); 2137 2138 /* The SD is sharing this channel. */ 2139 NXGE_DC_SET(set->shared.map, channel); 2140 set->shared.count++; 2141 2142 /* Soft Reset TxDMA A.9.6.2 */ 2143 nxge_grp_dc_remove(nxge, VP_BOUND_TX, channel); 2144 2145 /* 2146 * Initialize the DC-specific FZC control registers. 2147 * ----------------------------------------------------- 2148 */ 2149 if (nxge_init_fzc_tdc(nxge, channel) != NXGE_OK) { 2150 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 2151 "nxge_hio_tdc_share: FZC TDC failed: %d", channel)); 2152 return (-EIO); 2153 } 2154 2155 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_tdc_share")); 2156 2157 return (0); 2158 } 2159 2160 /* 2161 * nxge_hio_rdc_share 2162 * 2163 * Share an unused RDC channel. 2164 * 2165 * Arguments: 2166 * nxge 2167 * 2168 * Notes: 2169 * 2170 * This is the latest version of the procedure to 2171 * Reconfigure an Rx DMA channel: 2172 * 2173 * A.6.3 Reconfigure Rx DMA channel 2174 * Stop RxMAC A.9.2.6 2175 * Drain IPP Port A.9.3.6 2176 * Stop and reset RxDMA A.9.5.3 2177 * 2178 * This procedure will be executed by nxge_init_rxdma_channel() in the 2179 * guest domain: 2180 * 2181 * Initialize RxDMA A.9.5.4 2182 * Reconfigure RxDMA 2183 * Enable RxDMA A.9.5.5 2184 * 2185 * We will do this here, since the RDC is a canalis non grata: 2186 * Enable RxMAC A.9.2.10 2187 * 2188 * Context: 2189 * Service domain 2190 */ 2191 int 2192 nxge_hio_rdc_share( 2193 nxge_t *nxge, 2194 nxge_hio_vr_t *vr, 2195 int channel) 2196 { 2197 nxge_grp_set_t *set = &nxge->rx_set; 2198 nxge_rdc_grp_t *rdc_grp; 2199 2200 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_rdc_share")); 2201 2202 /* Disable interrupts. */ 2203 if (nxge_intr_remove(nxge, VP_BOUND_RX, channel) != NXGE_OK) { 2204 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_rdc_share: " 2205 "Failed to remove interrupt for RxDMA channel %d", 2206 channel)); 2207 return (NXGE_ERROR); 2208 } 2209 2210 /* Stop RxMAC = A.9.2.6 */ 2211 if (nxge_rx_mac_disable(nxge) != NXGE_OK) { 2212 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_rdc_share: " 2213 "Failed to disable RxMAC")); 2214 } 2215 2216 /* Drain IPP Port = A.9.3.6 */ 2217 (void) nxge_ipp_drain(nxge); 2218 2219 /* Stop and reset RxDMA = A.9.5.3 */ 2220 // De-assert EN: RXDMA_CFIG1[31] = 0 (DMC+00000 ) 2221 if (nxge_disable_rxdma_channel(nxge, channel) != NXGE_OK) { 2222 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_rdc_share: " 2223 "Failed to disable RxDMA channel %d", channel)); 2224 } 2225 2226 /* The SD is sharing this channel. */ 2227 NXGE_DC_SET(set->shared.map, channel); 2228 set->shared.count++; 2229 2230 // Assert RST: RXDMA_CFIG1[30] = 1 2231 nxge_grp_dc_remove(nxge, VP_BOUND_RX, channel); 2232 2233 /* 2234 * The guest domain will reconfigure the RDC later. 2235 * 2236 * But in the meantime, we must re-enable the Rx MAC so 2237 * that we can start receiving packets again on the 2238 * remaining RDCs: 2239 * 2240 * Enable RxMAC = A.9.2.10 2241 */ 2242 if (nxge_rx_mac_enable(nxge) != NXGE_OK) { 2243 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 2244 "nxge_hio_rdc_share: Rx MAC still disabled")); 2245 } 2246 2247 /* 2248 * Initialize the DC-specific FZC control registers. 2249 * ----------------------------------------------------- 2250 */ 2251 if (nxge_init_fzc_rdc(nxge, channel) != NXGE_OK) { 2252 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 2253 "nxge_hio_rdc_share: RZC RDC failed: %ld", channel)); 2254 return (-EIO); 2255 } 2256 2257 /* 2258 * Update the RDC group. 2259 */ 2260 rdc_grp = &nxge->pt_config.rdc_grps[vr->rdc_tbl]; 2261 NXGE_DC_SET(rdc_grp->map, channel); 2262 2263 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_rdc_share")); 2264 2265 return (0); 2266 } 2267 2268 /* 2269 * nxge_hio_dc_share 2270 * 2271 * Share a DMA channel with a guest domain. 2272 * 2273 * Arguments: 2274 * nxge 2275 * vr The VR that <channel> will belong to. 2276 * type Tx or Rx. 2277 * channel Channel to share 2278 * 2279 * Notes: 2280 * 2281 * Context: 2282 * Service domain 2283 */ 2284 int 2285 nxge_hio_dc_share( 2286 nxge_t *nxge, 2287 nxge_hio_vr_t *vr, 2288 mac_ring_type_t type, 2289 int channel) 2290 { 2291 nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 2292 nxge_hio_dc_t *dc; 2293 nxge_grp_t *group; 2294 int slot; 2295 2296 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_dc_share(%cdc %d", 2297 type == MAC_RING_TYPE_TX ? 't' : 'r', channel)); 2298 2299 2300 /* -------------------------------------------------- */ 2301 slot = (type == MAC_RING_TYPE_TX) ? 2302 nxge_hio_tdc_share(nxge, channel) : 2303 nxge_hio_rdc_share(nxge, vr, channel); 2304 2305 if (slot < 0) { 2306 if (type == MAC_RING_TYPE_RX) { 2307 nxge_hio_rdc_unshare(nxge, vr->rdc_tbl, channel); 2308 } else { 2309 nxge_hio_tdc_unshare(nxge, vr->tdc_tbl, channel); 2310 } 2311 return (slot); 2312 } 2313 2314 MUTEX_ENTER(&nhd->lock); 2315 2316 /* 2317 * Tag this channel. 2318 * -------------------------------------------------- 2319 */ 2320 dc = type == MAC_RING_TYPE_TX ? &nhd->tdc[channel] : &nhd->rdc[channel]; 2321 2322 dc->vr = vr; 2323 dc->channel = (nxge_channel_t)channel; 2324 2325 MUTEX_EXIT(&nhd->lock); 2326 2327 /* 2328 * vr->[t|r]x_group is used by the service domain to 2329 * keep track of its shared DMA channels. 2330 */ 2331 MUTEX_ENTER(&nxge->group_lock); 2332 group = (type == MAC_RING_TYPE_TX ? &vr->tx_group : &vr->rx_group); 2333 2334 dc->group = group; 2335 /* Initialize <group>, if necessary */ 2336 if (group->count == 0) { 2337 group->nxge = nxge; 2338 group->type = (type == MAC_RING_TYPE_TX) ? 2339 VP_BOUND_TX : VP_BOUND_RX; 2340 group->sequence = nhd->sequence++; 2341 group->active = B_TRUE; 2342 } 2343 2344 MUTEX_EXIT(&nxge->group_lock); 2345 2346 NXGE_ERROR_MSG((nxge, HIO_CTL, 2347 "DC share: %cDC %d was assigned to slot %d", 2348 type == MAC_RING_TYPE_TX ? 'T' : 'R', channel, slot)); 2349 2350 nxge_grp_dc_append(nxge, group, dc); 2351 2352 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_dc_share")); 2353 2354 return (0); 2355 } 2356 2357 /* 2358 * nxge_hio_tdc_unshare 2359 * 2360 * Unshare a TDC. 2361 * 2362 * Arguments: 2363 * nxge 2364 * channel The channel to unshare (add again). 2365 * 2366 * Notes: 2367 * 2368 * Context: 2369 * Service domain 2370 */ 2371 void 2372 nxge_hio_tdc_unshare( 2373 nxge_t *nxge, 2374 int dev_grpid, 2375 int channel) 2376 { 2377 nxge_grp_set_t *set = &nxge->tx_set; 2378 nxge_grp_t *group; 2379 int grpid; 2380 2381 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_tdc_unshare")); 2382 2383 NXGE_DC_RESET(set->shared.map, channel); 2384 set->shared.count--; 2385 2386 grpid = dev_grpid - nxge->pt_config.hw_config.def_mac_txdma_grpid; 2387 group = set->group[grpid]; 2388 2389 if ((nxge_grp_dc_add(nxge, group, VP_BOUND_TX, channel))) { 2390 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_tdc_unshare: " 2391 "Failed to initialize TxDMA channel %d", channel)); 2392 return; 2393 } 2394 2395 /* Re-add this interrupt. */ 2396 if (nxge_intr_add(nxge, VP_BOUND_TX, channel) != NXGE_OK) { 2397 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_tdc_unshare: " 2398 "Failed to add interrupt for TxDMA channel %d", channel)); 2399 } 2400 2401 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_tdc_unshare")); 2402 } 2403 2404 /* 2405 * nxge_hio_rdc_unshare 2406 * 2407 * Unshare an RDC: add it to the SD's RDC groups (tables). 2408 * 2409 * Arguments: 2410 * nxge 2411 * channel The channel to unshare (add again). 2412 * 2413 * Notes: 2414 * 2415 * Context: 2416 * Service domain 2417 */ 2418 void 2419 nxge_hio_rdc_unshare( 2420 nxge_t *nxge, 2421 int dev_grpid, 2422 int channel) 2423 { 2424 nxge_grp_set_t *set = &nxge->rx_set; 2425 nxge_grp_t *group; 2426 int grpid; 2427 2428 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_rdc_unshare")); 2429 2430 /* Stop RxMAC = A.9.2.6 */ 2431 if (nxge_rx_mac_disable(nxge) != NXGE_OK) { 2432 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_rdc_unshare: " 2433 "Failed to disable RxMAC")); 2434 } 2435 2436 /* Drain IPP Port = A.9.3.6 */ 2437 (void) nxge_ipp_drain(nxge); 2438 2439 /* Stop and reset RxDMA = A.9.5.3 */ 2440 // De-assert EN: RXDMA_CFIG1[31] = 0 (DMC+00000 ) 2441 if (nxge_disable_rxdma_channel(nxge, channel) != NXGE_OK) { 2442 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_rdc_unshare: " 2443 "Failed to disable RxDMA channel %d", channel)); 2444 } 2445 2446 NXGE_DC_RESET(set->shared.map, channel); 2447 set->shared.count--; 2448 2449 grpid = dev_grpid - nxge->pt_config.hw_config.def_mac_rxdma_grpid; 2450 group = set->group[grpid]; 2451 2452 /* 2453 * Assert RST: RXDMA_CFIG1[30] = 1 2454 * 2455 * Initialize RxDMA A.9.5.4 2456 * Reconfigure RxDMA 2457 * Enable RxDMA A.9.5.5 2458 */ 2459 if ((nxge_grp_dc_add(nxge, group, VP_BOUND_RX, channel))) { 2460 /* Be sure to re-enable the RX MAC. */ 2461 if (nxge_rx_mac_enable(nxge) != NXGE_OK) { 2462 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 2463 "nxge_hio_rdc_share: Rx MAC still disabled")); 2464 } 2465 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_hio_rdc_unshare: " 2466 "Failed to initialize RxDMA channel %d", channel)); 2467 return; 2468 } 2469 2470 /* 2471 * Enable RxMAC = A.9.2.10 2472 */ 2473 if (nxge_rx_mac_enable(nxge) != NXGE_OK) { 2474 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 2475 "nxge_hio_rdc_share: Rx MAC still disabled")); 2476 return; 2477 } 2478 2479 /* Re-add this interrupt. */ 2480 if (nxge_intr_add(nxge, VP_BOUND_RX, channel) != NXGE_OK) { 2481 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 2482 "nxge_hio_rdc_unshare: Failed to add interrupt for " 2483 "RxDMA CHANNEL %d", channel)); 2484 } 2485 2486 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_rdc_unshare")); 2487 } 2488 2489 /* 2490 * nxge_hio_dc_unshare 2491 * 2492 * Unshare (reuse) a DMA channel. 2493 * 2494 * Arguments: 2495 * nxge 2496 * vr The VR that <channel> belongs to. 2497 * type Tx or Rx. 2498 * channel The DMA channel to reuse. 2499 * 2500 * Notes: 2501 * 2502 * Context: 2503 * Service domain 2504 */ 2505 void 2506 nxge_hio_dc_unshare( 2507 nxge_t *nxge, 2508 nxge_hio_vr_t *vr, 2509 mac_ring_type_t type, 2510 int channel) 2511 { 2512 nxge_grp_t *group; 2513 nxge_hio_dc_t *dc; 2514 2515 NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_dc_unshare(%cdc %d)", 2516 type == MAC_RING_TYPE_TX ? 't' : 'r', channel)); 2517 2518 /* Unlink the channel from its group. */ 2519 /* -------------------------------------------------- */ 2520 group = (type == MAC_RING_TYPE_TX) ? &vr->tx_group : &vr->rx_group; 2521 NXGE_DC_RESET(group->map, channel); 2522 if ((dc = nxge_grp_dc_unlink(nxge, group, channel)) == 0) { 2523 NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 2524 "nxge_hio_dc_unshare(%d) failed", channel)); 2525 return; 2526 } 2527 2528 dc->vr = 0; 2529 dc->cookie = 0; 2530 2531 if (type == MAC_RING_TYPE_RX) { 2532 nxge_hio_rdc_unshare(nxge, vr->rdc_tbl, channel); 2533 } else { 2534 nxge_hio_tdc_unshare(nxge, vr->tdc_tbl, channel); 2535 } 2536 2537 NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_dc_unshare")); 2538 } 2539 2540 2541 /* 2542 * nxge_hio_rxdma_bind_intr(): 2543 * 2544 * For the guest domain driver, need to bind the interrupt group 2545 * and state to the rx_rcr_ring_t. 2546 */ 2547 2548 int 2549 nxge_hio_rxdma_bind_intr(nxge_t *nxge, rx_rcr_ring_t *ring, int channel) 2550 { 2551 nxge_hio_dc_t *dc; 2552 nxge_ldgv_t *control; 2553 nxge_ldg_t *group; 2554 nxge_ldv_t *device; 2555 2556 /* 2557 * Find the DMA channel. 2558 */ 2559 if (!(dc = nxge_grp_dc_find(nxge, VP_BOUND_RX, channel))) { 2560 return (NXGE_ERROR); 2561 } 2562 2563 /* 2564 * Get the control structure. 2565 */ 2566 control = nxge->ldgvp; 2567 if (control == NULL) { 2568 return (NXGE_ERROR); 2569 } 2570 2571 group = &control->ldgp[dc->ldg.vector]; 2572 device = &control->ldvp[dc->ldg.ldsv]; 2573 2574 MUTEX_ENTER(&ring->lock); 2575 ring->ldgp = group; 2576 ring->ldvp = device; 2577 MUTEX_EXIT(&ring->lock); 2578 2579 return (NXGE_OK); 2580 } 2581 #endif /* if defined(sun4v) */ 2582