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