xref: /illumos-gate/usr/src/uts/common/io/nxge/nxge_intr.c (revision e3d11eee)
1678453a8Sspeer /*
2678453a8Sspeer  * CDDL HEADER START
3678453a8Sspeer  *
4678453a8Sspeer  * The contents of this file are subject to the terms of the
5678453a8Sspeer  * Common Development and Distribution License (the "License").
6678453a8Sspeer  * You may not use this file except in compliance with the License.
7678453a8Sspeer  *
8678453a8Sspeer  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9678453a8Sspeer  * or http://www.opensolaris.org/os/licensing.
10678453a8Sspeer  * See the License for the specific language governing permissions
11678453a8Sspeer  * and limitations under the License.
12678453a8Sspeer  *
13678453a8Sspeer  * When distributing Covered Code, include this CDDL HEADER in each
14678453a8Sspeer  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15678453a8Sspeer  * If applicable, add the following below this CDDL HEADER, with the
16678453a8Sspeer  * fields enclosed by brackets "[]" replaced with your own identifying
17678453a8Sspeer  * information: Portions Copyright [yyyy] [name of copyright owner]
18678453a8Sspeer  *
19678453a8Sspeer  * CDDL HEADER END
20678453a8Sspeer  */
21678453a8Sspeer 
22678453a8Sspeer /*
230dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24678453a8Sspeer  * Use is subject to license terms.
25678453a8Sspeer  */
26678453a8Sspeer 
27678453a8Sspeer /*
28678453a8Sspeer  * nxge_intr.c
29678453a8Sspeer  *
30678453a8Sspeer  * This file manages the interrupts for a hybrid I/O (hio) device.
31678453a8Sspeer  * In the future, it may manage interrupts for all Neptune-based
32678453a8Sspeer  * devices.
33678453a8Sspeer  *
34678453a8Sspeer  */
35678453a8Sspeer 
36678453a8Sspeer #include <sys/nxge/nxge_impl.h>
37678453a8Sspeer #include <sys/nxge/nxge_hio.h>
38678453a8Sspeer 
39678453a8Sspeer /*
40678453a8Sspeer  * External prototypes
41678453a8Sspeer  */
42678453a8Sspeer 
43678453a8Sspeer /* The following function may be found in nxge_[t|r]xdma.c */
44*e3d11eeeSToomas Soome extern uint_t nxge_tx_intr(char *, char *);
45*e3d11eeeSToomas Soome extern uint_t nxge_rx_intr(char *, char *);
46678453a8Sspeer 
47678453a8Sspeer /*
48678453a8Sspeer  * Local prototypes
49678453a8Sspeer  */
50678453a8Sspeer static int nxge_intr_vec_find(nxge_t *, vpc_type_t, int);
51678453a8Sspeer 
52678453a8Sspeer /*
53678453a8Sspeer  * nxge_intr_add
54678453a8Sspeer  *
55678453a8Sspeer  *	Add <channel>'s interrupt.
56678453a8Sspeer  *
57678453a8Sspeer  * Arguments:
58678453a8Sspeer  * 	nxge
59678453a8Sspeer  * 	type	Tx or Rx
60678453a8Sspeer  * 	channel	The channel whose interrupt we want to add.
61678453a8Sspeer  *
62678453a8Sspeer  * Notes:
63678453a8Sspeer  *	Add here means: add a handler, enable, & arm the interrupt.
64678453a8Sspeer  *
65678453a8Sspeer  * Context:
66678453a8Sspeer  *	Service domain
67678453a8Sspeer  *
68678453a8Sspeer  */
69678453a8Sspeer nxge_status_t
nxge_intr_add(nxge_t * nxge,vpc_type_t type,int channel)70678453a8Sspeer nxge_intr_add(
71678453a8Sspeer 	nxge_t *nxge,
72678453a8Sspeer 	vpc_type_t type,
73678453a8Sspeer 	int channel)
74678453a8Sspeer {
75678453a8Sspeer 	nxge_intr_t	*interrupts; /* The global interrupt data. */
76678453a8Sspeer 	nxge_ldg_t	*group;	/* The logical device group data. */
77678453a8Sspeer 	nxge_ldv_t	*ldvp;
78*e3d11eeeSToomas Soome 	ddi_intr_handler_t *inthandler;
79678453a8Sspeer 	int		vector;
80678453a8Sspeer 	int		status1, status2;
81678453a8Sspeer 
82678453a8Sspeer 	char c = (type == VP_BOUND_TX ? 'T' : 'R');
83678453a8Sspeer 
84678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_intr_add"));
85678453a8Sspeer 
86678453a8Sspeer 	if ((vector = nxge_intr_vec_find(nxge, type, channel)) == -1) {
87678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
88678453a8Sspeer 		    "nxge_intr_add(%cDC %d): vector not found", c, channel));
89678453a8Sspeer 		return (NXGE_ERROR);
90678453a8Sspeer 	}
91678453a8Sspeer 
92678453a8Sspeer 	ldvp = &nxge->ldgvp->ldvp[vector];
93678453a8Sspeer 	group = ldvp->ldgp;
94678453a8Sspeer 
95678453a8Sspeer 	if (group->nldvs == 1) {
96*e3d11eeeSToomas Soome 		inthandler = group->ldvp->ldv_intr_handler;
97678453a8Sspeer 	} else if (group->nldvs > 1) {
98*e3d11eeeSToomas Soome 		inthandler = group->sys_intr_handler;
99*e3d11eeeSToomas Soome 	} else {
100*e3d11eeeSToomas Soome 		inthandler = NULL;
101678453a8Sspeer 	}
102678453a8Sspeer 
103678453a8Sspeer 	interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
104678453a8Sspeer 
105678453a8Sspeer 	status1 = DDI_SUCCESS;
106678453a8Sspeer 
107678453a8Sspeer 	if ((status2 = ddi_intr_add_handler(interrupts->htable[vector],
108*e3d11eeeSToomas Soome 	    inthandler, group->ldvp, nxge))
109678453a8Sspeer 	    != DDI_SUCCESS) {
110678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_add(%cDC %d): "
111678453a8Sspeer 		    "ddi_intr_add_handler(%d) returned %s",
112678453a8Sspeer 		    c, channel, vector, nxge_ddi_perror(status2)));
113678453a8Sspeer 		status1 += status2;
114678453a8Sspeer 	}
115678453a8Sspeer 
116678453a8Sspeer 	interrupts->intr_added++;
117678453a8Sspeer 
118678453a8Sspeer 	/* Enable the interrupt. */
119678453a8Sspeer 	if ((status2 = ddi_intr_enable(interrupts->htable[vector]))
120678453a8Sspeer 	    != DDI_SUCCESS) {
121678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_add(%cDC %d): "
122678453a8Sspeer 		    "ddi_intr_enable(%d) returned %s",
123678453a8Sspeer 		    c, channel, vector, nxge_ddi_perror(status2)));
124678453a8Sspeer 		status1 += status2;
125678453a8Sspeer 	}
126678453a8Sspeer 
127678453a8Sspeer 	if (status1 == DDI_SUCCESS) {
128678453a8Sspeer 		interrupts->intr_enabled = B_TRUE;
129678453a8Sspeer 
130678453a8Sspeer 		/* Finally, arm the interrupt. */
131678453a8Sspeer 		if (group->nldvs == 1) {
132678453a8Sspeer 			npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge);
133678453a8Sspeer 			(void) npi_intr_ldg_mgmt_set(handle, group->ldg,
134678453a8Sspeer 			    B_TRUE, group->ldg_timer);
135678453a8Sspeer 		}
136678453a8Sspeer 	}
137678453a8Sspeer 
138678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_add"));
139678453a8Sspeer 
140678453a8Sspeer 	return (NXGE_OK);
141678453a8Sspeer }
142678453a8Sspeer 
143678453a8Sspeer /*
144678453a8Sspeer  * nxge_intr_remove
145678453a8Sspeer  *
146678453a8Sspeer  *	Remove <channel>'s interrupt.
147678453a8Sspeer  *
148678453a8Sspeer  * Arguments:
149678453a8Sspeer  * 	nxge
150678453a8Sspeer  * 	type	Tx or Rx
151678453a8Sspeer  * 	channel	The channel whose interrupt we want to remove.
152678453a8Sspeer  *
153678453a8Sspeer  * Notes:
154678453a8Sspeer  *	Remove here means: disarm, disable, & remove the handler.
155678453a8Sspeer  *
156678453a8Sspeer  * Context:
157678453a8Sspeer  *	Service domain
158678453a8Sspeer  *
159678453a8Sspeer  */
160678453a8Sspeer nxge_status_t
nxge_intr_remove(nxge_t * nxge,vpc_type_t type,int channel)161678453a8Sspeer nxge_intr_remove(
162678453a8Sspeer 	nxge_t *nxge,
163678453a8Sspeer 	vpc_type_t type,
164678453a8Sspeer 	int channel)
165678453a8Sspeer {
166678453a8Sspeer 	nxge_intr_t	*interrupts; /* The global interrupt data. */
167678453a8Sspeer 	nxge_ldg_t	*group;	/* The logical device group data. */
168678453a8Sspeer 	nxge_ldv_t	*ldvp;
169678453a8Sspeer 
170678453a8Sspeer 	int		vector;
171678453a8Sspeer 	int		status1, status2;
172678453a8Sspeer 
173678453a8Sspeer 	char c = (type == VP_BOUND_TX ? 'T' : 'R');
174678453a8Sspeer 
175678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_intr_remove"));
176678453a8Sspeer 
177678453a8Sspeer 	if ((vector = nxge_intr_vec_find(nxge, type, channel)) == -1) {
178678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
179678453a8Sspeer 		    "nxge_intr_remove(%cDC %d): vector not found", c, channel));
180678453a8Sspeer 		return (NXGE_ERROR);
181678453a8Sspeer 	}
182678453a8Sspeer 
183678453a8Sspeer 	ldvp = &nxge->ldgvp->ldvp[vector];
184678453a8Sspeer 	group = ldvp->ldgp;
185678453a8Sspeer 
186678453a8Sspeer 	/* Disarm the interrupt. */
187678453a8Sspeer 	if (group->nldvs == 1) {
188678453a8Sspeer 		npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge);
189678453a8Sspeer 		group->arm = B_FALSE;
190678453a8Sspeer 		(void) npi_intr_ldg_mgmt_set(handle, group->ldg,
191678453a8Sspeer 		    B_TRUE, group->ldg_timer);
192678453a8Sspeer 		group->arm = B_TRUE; /* HIOXXX There IS a better way */
193678453a8Sspeer 	}
194678453a8Sspeer 
195678453a8Sspeer 	interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
196678453a8Sspeer 
197678453a8Sspeer 	status1 = DDI_SUCCESS;
198678453a8Sspeer 
199678453a8Sspeer 	/* Disable the interrupt. */
200678453a8Sspeer 	if ((status2 = ddi_intr_disable(interrupts->htable[vector]))
201678453a8Sspeer 	    != DDI_SUCCESS) {
202678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_remove(%cDC %d)"
203678453a8Sspeer 		    ": ddi_intr_disable(%d) returned %s",
204678453a8Sspeer 		    c, channel, vector, nxge_ddi_perror(status2)));
205678453a8Sspeer 		status1 += status2;
206678453a8Sspeer 	}
207678453a8Sspeer 
208678453a8Sspeer 	/* Remove the interrupt handler. */
209678453a8Sspeer 	if ((status2 = ddi_intr_remove_handler(interrupts->htable[vector]))
210678453a8Sspeer 	    != DDI_SUCCESS) {
211678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_remove(%cDC %d)"
212678453a8Sspeer 		    ": ddi_intr_remove_handler(%d) returned %s",
213678453a8Sspeer 		    c, channel, vector, nxge_ddi_perror(status2)));
214678453a8Sspeer 		status1 += status2;
215678453a8Sspeer 	}
216678453a8Sspeer 
217678453a8Sspeer 	if (status1 == DDI_SUCCESS) {
218678453a8Sspeer 		interrupts->intr_added--;
219678453a8Sspeer 		if (interrupts->intr_added == 0)
220678453a8Sspeer 			interrupts->intr_enabled = B_FALSE;
221678453a8Sspeer 	}
222678453a8Sspeer 
223678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_remove"));
224678453a8Sspeer 
225678453a8Sspeer 	return (NXGE_OK);
226678453a8Sspeer }
227678453a8Sspeer 
228678453a8Sspeer /*
229678453a8Sspeer  * nxge_intr_vec_find
230678453a8Sspeer  *
231678453a8Sspeer  *	Find the interrupt vector associated with <channel>.
232678453a8Sspeer  *
233678453a8Sspeer  * Arguments:
234678453a8Sspeer  * 	nxge
235678453a8Sspeer  * 	type	Tx or Rx
236678453a8Sspeer  * 	channel	The channel whose vector we want to find.
237678453a8Sspeer  *
238678453a8Sspeer  * Notes:
239678453a8Sspeer  *
240678453a8Sspeer  * Context:
241678453a8Sspeer  *	Service domain
242678453a8Sspeer  *
243678453a8Sspeer  */
244678453a8Sspeer static
245678453a8Sspeer int
nxge_intr_vec_find(nxge_t * nxge,vpc_type_t type,int channel)246678453a8Sspeer nxge_intr_vec_find(
247678453a8Sspeer 	nxge_t *nxge,
248678453a8Sspeer 	vpc_type_t type,
249678453a8Sspeer 	int channel)
250678453a8Sspeer {
251678453a8Sspeer 	nxge_hw_pt_cfg_t *hardware;
252678453a8Sspeer 	nxge_ldgv_t	*ldgvp;
253678453a8Sspeer 	nxge_ldv_t	*ldvp;
254678453a8Sspeer 
255678453a8Sspeer 	int		first, limit, vector;
256678453a8Sspeer 
257678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL,
258678453a8Sspeer 	    "==> nxge_intr_vec_find(%cDC %d)",
259678453a8Sspeer 	    type == VP_BOUND_TX ? 'T' : 'R', channel));
260678453a8Sspeer 
261678453a8Sspeer 	if (nxge->ldgvp == 0) {
262678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, HIO_CTL,
263678453a8Sspeer 		    "nxge_hio_intr_vec_find(%cDC %d): ldgvp == 0",
264678453a8Sspeer 		    type == VP_BOUND_TX ? 'T' : 'R', channel));
265678453a8Sspeer 		return (-1);
266678453a8Sspeer 	}
267678453a8Sspeer 
268678453a8Sspeer 	hardware = &nxge->pt_config.hw_config;
269678453a8Sspeer 
270678453a8Sspeer 	first = hardware->ldg_chn_start;
271678453a8Sspeer 	if (type == VP_BOUND_TX) {
272678453a8Sspeer 		first += 8;	/* HIOXXX N2/NIU hack */
273678453a8Sspeer 		limit = first + hardware->tdc.count;
274678453a8Sspeer 	} else {
275678453a8Sspeer 		limit = first + hardware->max_rdcs;
276678453a8Sspeer 	}
277678453a8Sspeer 
278678453a8Sspeer 	ldgvp = nxge->ldgvp;
279678453a8Sspeer 	for (vector = first; vector < limit; vector++) {
280678453a8Sspeer 		ldvp = &ldgvp->ldvp[vector];
281678453a8Sspeer 		if (ldvp->channel == channel)
282678453a8Sspeer 			break;
283678453a8Sspeer 	}
284678453a8Sspeer 
285678453a8Sspeer 	if (vector == limit) {
286678453a8Sspeer 		return (-1);
287678453a8Sspeer 	}
288678453a8Sspeer 
289678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_vec_find"));
290678453a8Sspeer 
291678453a8Sspeer 	return (vector);
292678453a8Sspeer }
293678453a8Sspeer 
294678453a8Sspeer /*
295678453a8Sspeer  * ---------------------------------------------------------------------
296678453a8Sspeer  * HIO-specific interrupt functions.
297678453a8Sspeer  * ---------------------------------------------------------------------
298678453a8Sspeer  */
299678453a8Sspeer 
300678453a8Sspeer /*
301678453a8Sspeer  * nxge_hio_intr_add
302678453a8Sspeer  *
303678453a8Sspeer  *	Add <channel>'s interrupt.
304678453a8Sspeer  *
305678453a8Sspeer  * Arguments:
306678453a8Sspeer  * 	nxge
307678453a8Sspeer  * 	type	Tx or Rx
308678453a8Sspeer  * 	channel	The channel whose interrupt we want to remove.
309678453a8Sspeer  *
310678453a8Sspeer  * Notes:
311678453a8Sspeer  *
312678453a8Sspeer  * Context:
313678453a8Sspeer  *	Guest domain
314678453a8Sspeer  *
315678453a8Sspeer  */
316678453a8Sspeer nxge_status_t
nxge_hio_intr_add(nxge_t * nxge,vpc_type_t type,int channel)317678453a8Sspeer nxge_hio_intr_add(
318678453a8Sspeer 	nxge_t *nxge,
319678453a8Sspeer 	vpc_type_t type,
320678453a8Sspeer 	int channel)
321678453a8Sspeer {
322678453a8Sspeer 	nxge_hio_dc_t	*dc;	/* The relevant DMA channel data structure. */
323678453a8Sspeer 	nxge_intr_t	*interrupts; /* The global interrupt data. */
324678453a8Sspeer 	nxge_ldg_t	*group;	/* The logical device group data. */
325*e3d11eeeSToomas Soome 	ddi_intr_handler_t *inthandler;
326678453a8Sspeer 
327678453a8Sspeer 	int		vector;	/* A shorthand variable */
328678453a8Sspeer 	int		ddi_status; /* The response to ddi_intr_add_handler */
329678453a8Sspeer 
330678453a8Sspeer 	char c = (type == VP_BOUND_TX ? 'T' : 'R');
331678453a8Sspeer 
332678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL,
333678453a8Sspeer 	    "==> nxge_hio_intr_add(%cDC %d)", c, channel));
334678453a8Sspeer 
335678453a8Sspeer 	if (nxge->ldgvp == 0) {
336678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, HIO_CTL,
337678453a8Sspeer 		    "nxge_hio_intr_add(%cDC %d): ldgvp == 0", c, channel));
338678453a8Sspeer 		return (NXGE_ERROR);
339678453a8Sspeer 	}
340678453a8Sspeer 
341678453a8Sspeer 	if ((dc = nxge_grp_dc_find(nxge, type, channel)) == 0) {
342678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, HIO_CTL,
343678453a8Sspeer 		    "nxge_hio_intr_add: find(%s, %d) failed", c, channel));
344678453a8Sspeer 		return (NXGE_ERROR);
345678453a8Sspeer 	}
346678453a8Sspeer 
347678453a8Sspeer 	/* 'nxge_intr_type' is a bad name for this data structure. */
348678453a8Sspeer 	interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
349678453a8Sspeer 
350678453a8Sspeer 	/* Set <vector> here to make the following code easier to read. */
351678453a8Sspeer 	vector = dc->ldg.vector;
352678453a8Sspeer 
353678453a8Sspeer 	group = &nxge->ldgvp->ldgp[vector];
354678453a8Sspeer 
355678453a8Sspeer 	if (group->nldvs == 1) {
356*e3d11eeeSToomas Soome 		inthandler = group->ldvp->ldv_intr_handler;
357678453a8Sspeer 	} else if (group->nldvs > 1) {
358*e3d11eeeSToomas Soome 		inthandler = group->sys_intr_handler;
359*e3d11eeeSToomas Soome 	} else {
360*e3d11eeeSToomas Soome 		inthandler = NULL;
361678453a8Sspeer 	}
362678453a8Sspeer 
363678453a8Sspeer 	if ((ddi_status = ddi_intr_add_handler(interrupts->htable[vector],
364*e3d11eeeSToomas Soome 	    inthandler, group->ldvp, nxge))
365678453a8Sspeer 	    != DDI_SUCCESS) {
366678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
367678453a8Sspeer 		    "nxge_hio_intr_add(%cDC %d): "
368678453a8Sspeer 		    "ddi_intr_add_handler(%d) returned %s",
369678453a8Sspeer 		    c, channel, vector, nxge_ddi_perror(ddi_status)));
370678453a8Sspeer 		return (NXGE_ERROR);
371678453a8Sspeer 	}
372678453a8Sspeer 
373678453a8Sspeer 	interrupts->intr_added++;
374678453a8Sspeer 
375678453a8Sspeer 	/* Enable the interrupt. */
376678453a8Sspeer 	if ((ddi_status = ddi_intr_enable(interrupts->htable[vector]))
377678453a8Sspeer 	    != DDI_SUCCESS) {
378678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
379678453a8Sspeer 		    "nxge_hio_intr_add(%cDC %d): "
380678453a8Sspeer 		    "ddi_intr_enable(%d) returned %s",
381678453a8Sspeer 		    c, channel, vector, nxge_ddi_perror(ddi_status)));
382678453a8Sspeer 		return (NXGE_ERROR);
383678453a8Sspeer 	}
384678453a8Sspeer 
385678453a8Sspeer 	interrupts->intr_enabled = B_TRUE;
386678453a8Sspeer 
387e759c33aSMichael Speer 	/*
388e759c33aSMichael Speer 	 * Note: RDC interrupts will be armed in nxge_m_start(). This
389e759c33aSMichael Speer 	 * prevents us from getting an interrupt before we are ready
390e759c33aSMichael Speer 	 * to process packets.
391e759c33aSMichael Speer 	 */
392e759c33aSMichael Speer 	if (type == VP_BOUND_TX) {
393e759c33aSMichael Speer 		nxge_hio_ldgimgn(nxge, group);
394e759c33aSMichael Speer 	}
395678453a8Sspeer 
396678453a8Sspeer 	dc->interrupting = B_TRUE;
397678453a8Sspeer 
398678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_add"));
399678453a8Sspeer 
400678453a8Sspeer 	return (NXGE_OK);
401678453a8Sspeer }
402678453a8Sspeer 
403678453a8Sspeer /*
404678453a8Sspeer  * nxge_hio_intr_remove
405678453a8Sspeer  *
406678453a8Sspeer  *	Remove <channel>'s interrupt.
407678453a8Sspeer  *
408678453a8Sspeer  * Arguments:
409678453a8Sspeer  * 	nxge
410678453a8Sspeer  * 	type	Tx or Rx
411678453a8Sspeer  * 	channel	The channel whose interrupt we want to remove.
412678453a8Sspeer  *
413678453a8Sspeer  * Notes:
414678453a8Sspeer  *
415678453a8Sspeer  * Context:
416678453a8Sspeer  *	Guest domain
417678453a8Sspeer  *
418678453a8Sspeer  */
419678453a8Sspeer nxge_status_t
nxge_hio_intr_remove(nxge_t * nxge,vpc_type_t type,int channel)420678453a8Sspeer nxge_hio_intr_remove(
421678453a8Sspeer 	nxge_t *nxge,
422678453a8Sspeer 	vpc_type_t type,
423678453a8Sspeer 	int channel)
424678453a8Sspeer {
425678453a8Sspeer 	nxge_hio_dc_t	*dc;	/* The relevant DMA channel data structure. */
426678453a8Sspeer 	nxge_intr_t	*interrupts; /* The global interrupt data. */
427678453a8Sspeer 	nxge_ldg_t	*group;	/* The logical device group data. */
428678453a8Sspeer 
429678453a8Sspeer 	int		vector;	/* A shorthand variable */
430678453a8Sspeer 	int		status1, status2;
431678453a8Sspeer 
432678453a8Sspeer 	char c = (type == VP_BOUND_TX ? 'T' : 'R');
433678453a8Sspeer 
434678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL,
435678453a8Sspeer 	    "==> nxge_hio_intr_remove(%cDC %d)", c, channel));
436678453a8Sspeer 
437678453a8Sspeer 	if (nxge->ldgvp == 0) {
438678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, HIO_CTL,
439678453a8Sspeer 		    "nxge_hio_intr_remove(%cDC %d): ldgvp == 0", c, channel));
440678453a8Sspeer 		return (NXGE_ERROR);
441678453a8Sspeer 	}
442678453a8Sspeer 
443678453a8Sspeer 	if ((dc = nxge_grp_dc_find(nxge, type, channel)) == 0) {
444678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
445678453a8Sspeer 		    "nxge_hio_intr_remove(%cDC %d): DC FIND failed",
446678453a8Sspeer 		    c, channel));
447678453a8Sspeer 		return (NXGE_ERROR);
448678453a8Sspeer 	}
449678453a8Sspeer 
450678453a8Sspeer 	if (dc->interrupting == B_FALSE) {
451678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, HIO_CTL,
452678453a8Sspeer 		    "nxge_hio_intr_remove(%cDC %d): interrupting == FALSE",
453678453a8Sspeer 		    c, channel));
454678453a8Sspeer 		return (NXGE_OK);
455678453a8Sspeer 	}
456678453a8Sspeer 
457678453a8Sspeer 	/* 'nxge_intr_type' is a bad name for this data structure. */
458678453a8Sspeer 	interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
459678453a8Sspeer 
460678453a8Sspeer 	/* Set <vector> here to make the following code easier to read. */
461678453a8Sspeer 	vector = dc->ldg.vector;
462678453a8Sspeer 
463678453a8Sspeer 	group = &nxge->ldgvp->ldgp[vector];
464678453a8Sspeer 
465678453a8Sspeer 	/* Disarm the interrupt. */
466678453a8Sspeer 	group->arm = B_FALSE;
467678453a8Sspeer 	nxge_hio_ldgimgn(nxge, group);
468678453a8Sspeer 	group->arm = B_TRUE;	/* HIOXXX There IS a better way */
469678453a8Sspeer 
470678453a8Sspeer 	status1 = DDI_SUCCESS;
471678453a8Sspeer 
472678453a8Sspeer 	/* Disable the interrupt. */
473678453a8Sspeer 	if ((status2 = ddi_intr_disable(interrupts->htable[vector]))
474678453a8Sspeer 	    != DDI_SUCCESS) {
475678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
476678453a8Sspeer 		    "nxge_hio_intr_remove(%cDC %d): "
477678453a8Sspeer 		    "ddi_intr_disable(%d) returned %s",
478678453a8Sspeer 		    c, channel, vector, nxge_ddi_perror(status2)));
479678453a8Sspeer 		status1 += status2;
480678453a8Sspeer 	}
481678453a8Sspeer 
482678453a8Sspeer 	/* Remove the interrupt handler. */
483678453a8Sspeer 	if ((status2 = ddi_intr_remove_handler(interrupts->htable[vector]))
484678453a8Sspeer 	    != DDI_SUCCESS) {
485678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
486678453a8Sspeer 		    "nxge_hio_intr_remove(%cDC %d): "
487678453a8Sspeer 		    "ddi_intr_remove_handle(%d) returned %s",
488678453a8Sspeer 		    c, channel, vector, nxge_ddi_perror(status2)));
489678453a8Sspeer 		status1 += status2;
490678453a8Sspeer 	}
491678453a8Sspeer 
492678453a8Sspeer 	if (status1 == DDI_SUCCESS) {
493678453a8Sspeer 		dc->interrupting = B_FALSE;
494678453a8Sspeer 
495678453a8Sspeer 		interrupts->intr_added--;
496678453a8Sspeer 		if (interrupts->intr_added == 0)
497678453a8Sspeer 			interrupts->intr_enabled = B_FALSE;
498678453a8Sspeer 	}
499678453a8Sspeer 
500678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_remove"));
501678453a8Sspeer 
502678453a8Sspeer 	return (NXGE_OK);
503678453a8Sspeer }
504678453a8Sspeer 
505678453a8Sspeer /*
506678453a8Sspeer  * nxge_hio_intr_init
507678453a8Sspeer  *
508678453a8Sspeer  *	Initialize interrupts in a guest domain.
509678453a8Sspeer  *
510678453a8Sspeer  * Arguments:
511678453a8Sspeer  * 	nxge
512678453a8Sspeer  *
513678453a8Sspeer  * Notes:
514678453a8Sspeer  *
515678453a8Sspeer  * Context:
516678453a8Sspeer  *	Guest domain
517678453a8Sspeer  *
518678453a8Sspeer  */
519678453a8Sspeer nxge_status_t
nxge_hio_intr_init(nxge_t * nxge)520678453a8Sspeer nxge_hio_intr_init(
521678453a8Sspeer 	nxge_t *nxge)
522678453a8Sspeer {
523678453a8Sspeer 	int		*prop_val;
524678453a8Sspeer 	uint_t		prop_len;
525678453a8Sspeer 
526678453a8Sspeer 	nxge_intr_t	*interrupts;
527678453a8Sspeer 
528678453a8Sspeer 	int		intr_type, behavior;
529678453a8Sspeer 	int		nintrs, navail, nactual;
530678453a8Sspeer 	int		inum = 0;
531678453a8Sspeer 	int		ddi_status = DDI_SUCCESS;
532678453a8Sspeer 
533678453a8Sspeer 	nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
534678453a8Sspeer 	int i;
535678453a8Sspeer 
536678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_intr_init"));
537678453a8Sspeer 
538678453a8Sspeer 	/* Look up the "interrupts" property. */
539678453a8Sspeer 	if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, nxge->dip, 0,
540678453a8Sspeer 	    "interrupts", &prop_val, &prop_len)) != DDI_PROP_SUCCESS) {
541678453a8Sspeer 		NXGE_ERROR_MSG((nxge, HIO_CTL,
542678453a8Sspeer 		    "==> nxge_hio_intr_init(obp): no 'interrupts' property"));
543678453a8Sspeer 		return (NXGE_ERROR);
544678453a8Sspeer 	}
545678453a8Sspeer 
546678453a8Sspeer 	/*
547678453a8Sspeer 	 * For each device assigned, the content of each interrupts
548678453a8Sspeer 	 * property is its logical device group.
549678453a8Sspeer 	 *
550678453a8Sspeer 	 * Assignment of interrupts property is in the the following
551678453a8Sspeer 	 * order:
552678453a8Sspeer 	 *
553678453a8Sspeer 	 * two receive channels
554678453a8Sspeer 	 * two transmit channels
555678453a8Sspeer 	 */
556678453a8Sspeer 	for (i = 0; i < prop_len; i++) {
557678453a8Sspeer 		hardware->ldg[i] = prop_val[i];
558678453a8Sspeer 		NXGE_DEBUG_MSG((nxge, HIO_CTL,
559678453a8Sspeer 		    "==> nxge_hio_intr_init(obp): F%d: interrupt #%d, ldg %d",
560678453a8Sspeer 		    nxge->function_num, i, hardware->ldg[i]));
561678453a8Sspeer 	}
562678453a8Sspeer 	ddi_prop_free(prop_val);
563678453a8Sspeer 
564678453a8Sspeer 	hardware->max_grpids = prop_len;
565678453a8Sspeer 	hardware->max_ldgs = prop_len;
566678453a8Sspeer 	hardware->ldg_chn_start = 0;
567678453a8Sspeer 
568678453a8Sspeer 	/* ----------------------------------------------------- */
569678453a8Sspeer 	interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
570678453a8Sspeer 
571678453a8Sspeer 	interrupts->intr_registered = B_FALSE;
572678453a8Sspeer 	interrupts->intr_enabled = B_FALSE;
573678453a8Sspeer 	interrupts->start_inum = 0;
574678453a8Sspeer 
575678453a8Sspeer 	ddi_status = ddi_intr_get_supported_types(
576678453a8Sspeer 	    nxge->dip, &interrupts->intr_types);
577678453a8Sspeer 	if (ddi_status != DDI_SUCCESS) {
578678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
579678453a8Sspeer 		    "ddi_intr_get_supported_types() returned 0x%x, "
580678453a8Sspeer 		    "types = 0x%x", ddi_status, interrupts->intr_types));
581678453a8Sspeer 		return (NXGE_ERROR);
582678453a8Sspeer 	}
583678453a8Sspeer 
584678453a8Sspeer 	NXGE_ERROR_MSG((nxge, HIO_CTL, "ddi_intr_get_supported_types() "
585678453a8Sspeer 	    "returned 0x%x, types = 0x%x", ddi_status, interrupts->intr_types));
586678453a8Sspeer 
587678453a8Sspeer 	/* HIOXXX hack */
588678453a8Sspeer 	interrupts->intr_type = DDI_INTR_TYPE_FIXED;
589678453a8Sspeer 	/* HIOXXX hack */
590678453a8Sspeer 
591678453a8Sspeer 	intr_type = interrupts->intr_type;
592678453a8Sspeer 
593678453a8Sspeer 	ddi_status = ddi_intr_get_navail(nxge->dip, intr_type, &navail);
594678453a8Sspeer 	if (ddi_status != DDI_SUCCESS) {
595678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
596678453a8Sspeer 		    "ddi_intr_get_navail() returned %s, navail: %d",
597678453a8Sspeer 		    ddi_status == DDI_FAILURE ? "DDI_FAILURE" :
598678453a8Sspeer 		    "DDI_INTR_NOTFOUND", navail));
599678453a8Sspeer 		return (NXGE_ERROR);
600678453a8Sspeer 	}
601678453a8Sspeer 
602678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL,
603678453a8Sspeer 	    "nxge_hio_intr_init: number of available interrupts: %d", navail));
604678453a8Sspeer 
605678453a8Sspeer 	ddi_status = ddi_intr_get_nintrs(nxge->dip, intr_type, &nintrs);
606678453a8Sspeer 	if (ddi_status != DDI_SUCCESS) {
607678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
608678453a8Sspeer 		    "ddi_intr_get_nintrs() returned %s, nintrs: %d",
609678453a8Sspeer 		    ddi_status == DDI_FAILURE ? "DDI_FAILURE" :
610678453a8Sspeer 		    "DDI_INTR_NOTFOUND", nintrs));
611678453a8Sspeer 		return (NXGE_ERROR);
612678453a8Sspeer 	}
613678453a8Sspeer 
614678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL,
615678453a8Sspeer 	    "nxge_hio_intr_init: number of interrupts: %d", nintrs));
616678453a8Sspeer 
617678453a8Sspeer 	interrupts->intr_size = navail * sizeof (ddi_intr_handle_t);
618678453a8Sspeer 	interrupts->htable = kmem_alloc(interrupts->intr_size, KM_SLEEP);
619678453a8Sspeer 
620678453a8Sspeer 	/*
621678453a8Sspeer 	 * When <behavior> is set to  DDI_INTR_ALLOC_STRICT,
622678453a8Sspeer 	 * ddi_intr_alloc() succeeds if and only if <navail>
623678453a8Sspeer 	 * interrupts are are allocated. Otherwise, it fails.
624678453a8Sspeer 	 */
625678453a8Sspeer 	behavior = ((intr_type == DDI_INTR_TYPE_FIXED) ?
626678453a8Sspeer 	    DDI_INTR_ALLOC_STRICT : DDI_INTR_ALLOC_NORMAL);
627678453a8Sspeer 
628678453a8Sspeer 	ddi_status = ddi_intr_alloc(nxge->dip, interrupts->htable, intr_type,
629678453a8Sspeer 	    inum, navail, &nactual, behavior);
630678453a8Sspeer 	if (ddi_status != DDI_SUCCESS) {
631678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
632678453a8Sspeer 		    "ddi_intr_alloc() returned 0x%x%, "
633678453a8Sspeer 		    "number allocated: %d", ddi_status, nactual));
634678453a8Sspeer 		return (NXGE_ERROR);
635678453a8Sspeer 	}
636678453a8Sspeer 
637678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL,
638678453a8Sspeer 	    "nxge_hio_intr_init: number of interrupts allocated: %d", nactual));
639678453a8Sspeer 
640678453a8Sspeer 	/* <ninterrupts> is a dead variable: we may as well use it. */
641678453a8Sspeer 	hardware->ninterrupts = nactual;
642678453a8Sspeer 
643678453a8Sspeer 	/* FOI: Get the interrupt priority. */
644678453a8Sspeer 	if ((ddi_status = ddi_intr_get_pri(interrupts->htable[0],
645678453a8Sspeer 	    (uint_t *)&interrupts->pri)) != DDI_SUCCESS) {
646678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
647678453a8Sspeer 		    " ddi_intr_get_pri() failed: %d", ddi_status));
648678453a8Sspeer 	}
649678453a8Sspeer 
650678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL,
651678453a8Sspeer 	    "nxge_hio_intr_init: interrupt priority: %d", interrupts->pri));
652678453a8Sspeer 
653678453a8Sspeer 	/* FOI: Get our interrupt capability flags. */
654678453a8Sspeer 	if ((ddi_status = ddi_intr_get_cap(interrupts->htable[0],
655678453a8Sspeer 	    &interrupts->intr_cap)) != DDI_SUCCESS) {
656678453a8Sspeer 		NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
657678453a8Sspeer 		    "ddi_intr_get_cap() failed: %d", ddi_status));
658678453a8Sspeer 	}
659678453a8Sspeer 
660678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL,
661678453a8Sspeer 	    "nxge_hio_intr_init: interrupt capabilities: %d",
662678453a8Sspeer 	    interrupts->intr_cap));
663678453a8Sspeer 
664678453a8Sspeer 	interrupts->intr_registered = B_TRUE;
665678453a8Sspeer 
666678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_init"));
667678453a8Sspeer 
668678453a8Sspeer 	return (NXGE_OK);
669678453a8Sspeer }
670678453a8Sspeer 
671678453a8Sspeer /*
672678453a8Sspeer  * nxge_hio_intr_uninit
673678453a8Sspeer  *
674678453a8Sspeer  *	Uninitialize interrupts in a guest domain.
675678453a8Sspeer  *
676678453a8Sspeer  * Arguments:
677678453a8Sspeer  * 	nxge
678678453a8Sspeer  *
679678453a8Sspeer  * Notes:
680678453a8Sspeer  *
681678453a8Sspeer  * Context:
682678453a8Sspeer  *	Guest domain
683678453a8Sspeer  */
684678453a8Sspeer void
nxge_hio_intr_uninit(nxge_t * nxge)685678453a8Sspeer nxge_hio_intr_uninit(
686678453a8Sspeer 	nxge_t *nxge)
687678453a8Sspeer {
688678453a8Sspeer 	nxge_hw_pt_cfg_t *hardware;
689678453a8Sspeer 	nxge_intr_t *interrupts;
690678453a8Sspeer 	nxge_ldgv_t *control;
691678453a8Sspeer 	int i;
692678453a8Sspeer 
693678453a8Sspeer 	NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_intr_uninit"));
694678453a8Sspeer 
695678453a8Sspeer 	/* ----------------------------------------------------- */
696678453a8Sspeer 	interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
697678453a8Sspeer 
698678453a8Sspeer 	/*
699678453a8Sspeer 	 * If necessary, disable any currently active interrupts.
700678453a8Sspeer 	 */
701678453a8Sspeer 	if (interrupts->intr_enabled) {
702678453a8Sspeer 		nxge_grp_set_t *set;
703678453a8Sspeer 		nxge_grp_t *group;
704678453a8Sspeer 		int channel;
705678453a8Sspeer 
706