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