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