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