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