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 /*
23*0dc2366fSVenugopal 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 */
44678453a8Sspeer extern uint_t nxge_tx_intr(void *, void *);
45678453a8Sspeer extern uint_t nxge_rx_intr(void *, void *);
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;
78678453a8Sspeer
79678453a8Sspeer uint_t *inthandler; /* A parameter to ddi_intr_add_handler */
80678453a8Sspeer int vector;
81678453a8Sspeer int status1, status2;
82678453a8Sspeer
83678453a8Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R');
84678453a8Sspeer
85678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_intr_add"));
86678453a8Sspeer
87678453a8Sspeer if ((vector = nxge_intr_vec_find(nxge, type, channel)) == -1) {
88678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
89678453a8Sspeer "nxge_intr_add(%cDC %d): vector not found", c, channel));
90678453a8Sspeer return (NXGE_ERROR);
91678453a8Sspeer }
92678453a8Sspeer
93678453a8Sspeer ldvp = &nxge->ldgvp->ldvp[vector];
94678453a8Sspeer group = ldvp->ldgp;
95678453a8Sspeer
96678453a8Sspeer if (group->nldvs == 1) {
97678453a8Sspeer inthandler = (uint_t *)group->ldvp->ldv_intr_handler;
98678453a8Sspeer } else if (group->nldvs > 1) {
99678453a8Sspeer inthandler = (uint_t *)group->sys_intr_handler;
100678453a8Sspeer }
101678453a8Sspeer
102678453a8Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
103678453a8Sspeer
104678453a8Sspeer status1 = DDI_SUCCESS;
105678453a8Sspeer
106678453a8Sspeer if ((status2 = ddi_intr_add_handler(interrupts->htable[vector],
107678453a8Sspeer (ddi_intr_handler_t *)inthandler, group->ldvp, nxge))
108678453a8Sspeer != DDI_SUCCESS) {
109678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_add(%cDC %d): "
110678453a8Sspeer "ddi_intr_add_handler(%d) returned %s",
111678453a8Sspeer c, channel, vector, nxge_ddi_perror(status2)));
112678453a8Sspeer status1 += status2;
113678453a8Sspeer }
114678453a8Sspeer
115678453a8Sspeer interrupts->intr_added++;
116678453a8Sspeer
117678453a8Sspeer /* Enable the interrupt. */
118678453a8Sspeer if ((status2 = ddi_intr_enable(interrupts->htable[vector]))
119678453a8Sspeer != DDI_SUCCESS) {
120678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_add(%cDC %d): "
121678453a8Sspeer "ddi_intr_enable(%d) returned %s",
122678453a8Sspeer c, channel, vector, nxge_ddi_perror(status2)));
123678453a8Sspeer status1 += status2;
124678453a8Sspeer }
125678453a8Sspeer
126678453a8Sspeer if (status1 == DDI_SUCCESS) {
127678453a8Sspeer interrupts->intr_enabled = B_TRUE;
128678453a8Sspeer
129678453a8Sspeer /* Finally, arm the interrupt. */
130678453a8Sspeer if (group->nldvs == 1) {
131678453a8Sspeer npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge);
132678453a8Sspeer (void) npi_intr_ldg_mgmt_set(handle, group->ldg,
133678453a8Sspeer B_TRUE, group->ldg_timer);
134678453a8Sspeer }
135678453a8Sspeer }
136678453a8Sspeer
137678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_add"));
138678453a8Sspeer
139678453a8Sspeer return (NXGE_OK);
140678453a8Sspeer }
141678453a8Sspeer
142678453a8Sspeer /*
143678453a8Sspeer * nxge_intr_remove
144678453a8Sspeer *
145678453a8Sspeer * Remove <channel>'s interrupt.
146678453a8Sspeer *
147678453a8Sspeer * Arguments:
148678453a8Sspeer * nxge
149678453a8Sspeer * type Tx or Rx
150678453a8Sspeer * channel The channel whose interrupt we want to remove.
151678453a8Sspeer *
152678453a8Sspeer * Notes:
153678453a8Sspeer * Remove here means: disarm, disable, & remove the handler.
154678453a8Sspeer *
155678453a8Sspeer * Context:
156678453a8Sspeer * Service domain
157678453a8Sspeer *
158678453a8Sspeer */
159678453a8Sspeer nxge_status_t
nxge_intr_remove(nxge_t * nxge,vpc_type_t type,int channel)160678453a8Sspeer nxge_intr_remove(
161678453a8Sspeer nxge_t *nxge,
162678453a8Sspeer vpc_type_t type,
163678453a8Sspeer int channel)
164678453a8Sspeer {
165678453a8Sspeer nxge_intr_t *interrupts; /* The global interrupt data. */
166678453a8Sspeer nxge_ldg_t *group; /* The logical device group data. */
167678453a8Sspeer nxge_ldv_t *ldvp;
168678453a8Sspeer
169678453a8Sspeer int vector;
170678453a8Sspeer int status1, status2;
171678453a8Sspeer
172678453a8Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R');
173678453a8Sspeer
174678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_intr_remove"));
175678453a8Sspeer
176678453a8Sspeer if ((vector = nxge_intr_vec_find(nxge, type, channel)) == -1) {
177678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
178678453a8Sspeer "nxge_intr_remove(%cDC %d): vector not found", c, channel));
179678453a8Sspeer return (NXGE_ERROR);
180678453a8Sspeer }
181678453a8Sspeer
182678453a8Sspeer ldvp = &nxge->ldgvp->ldvp[vector];
183678453a8Sspeer group = ldvp->ldgp;
184678453a8Sspeer
185678453a8Sspeer /* Disarm the interrupt. */
186678453a8Sspeer if (group->nldvs == 1) {
187678453a8Sspeer npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge);
188678453a8Sspeer group->arm = B_FALSE;
189678453a8Sspeer (void) npi_intr_ldg_mgmt_set(handle, group->ldg,
190678453a8Sspeer B_TRUE, group->ldg_timer);
191678453a8Sspeer group->arm = B_TRUE; /* HIOXXX There IS a better way */
192678453a8Sspeer }
193678453a8Sspeer
194678453a8Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
195678453a8Sspeer
196678453a8Sspeer status1 = DDI_SUCCESS;
197678453a8Sspeer
198678453a8Sspeer /* Disable the interrupt. */
199678453a8Sspeer if ((status2 = ddi_intr_disable(interrupts->htable[vector]))
200678453a8Sspeer != DDI_SUCCESS) {
201678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_remove(%cDC %d)"
202678453a8Sspeer ": ddi_intr_disable(%d) returned %s",
203678453a8Sspeer c, channel, vector, nxge_ddi_perror(status2)));
204678453a8Sspeer status1 += status2;
205678453a8Sspeer }
206678453a8Sspeer
207678453a8Sspeer /* Remove the interrupt handler. */
208678453a8Sspeer if ((status2 = ddi_intr_remove_handler(interrupts->htable[vector]))
209678453a8Sspeer != DDI_SUCCESS) {
210678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_remove(%cDC %d)"
211678453a8Sspeer ": ddi_intr_remove_handler(%d) returned %s",
212678453a8Sspeer c, channel, vector, nxge_ddi_perror(status2)));
213678453a8Sspeer status1 += status2;
214678453a8Sspeer }
215678453a8Sspeer
216678453a8Sspeer if (status1 == DDI_SUCCESS) {
217678453a8Sspeer interrupts->intr_added--;
218678453a8Sspeer if (interrupts->intr_added == 0)
219678453a8Sspeer interrupts->intr_enabled = B_FALSE;
220678453a8Sspeer }
221678453a8Sspeer
222678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_remove"));
223678453a8Sspeer
224678453a8Sspeer return (NXGE_OK);
225678453a8Sspeer }
226678453a8Sspeer
227678453a8Sspeer /*
228678453a8Sspeer * nxge_intr_vec_find
229678453a8Sspeer *
230678453a8Sspeer * Find the interrupt vector associated with <channel>.
231678453a8Sspeer *
232678453a8Sspeer * Arguments:
233678453a8Sspeer * nxge
234678453a8Sspeer * type Tx or Rx
235678453a8Sspeer * channel The channel whose vector we want to find.
236678453a8Sspeer *
237678453a8Sspeer * Notes:
238678453a8Sspeer *
239678453a8Sspeer * Context:
240678453a8Sspeer * Service domain
241678453a8Sspeer *
242678453a8Sspeer */
243678453a8Sspeer static
244678453a8Sspeer int
nxge_intr_vec_find(nxge_t * nxge,vpc_type_t type,int channel)245678453a8Sspeer nxge_intr_vec_find(
246678453a8Sspeer nxge_t *nxge,
247678453a8Sspeer vpc_type_t type,
248678453a8Sspeer int channel)
249678453a8Sspeer {
250678453a8Sspeer nxge_hw_pt_cfg_t *hardware;
251678453a8Sspeer nxge_ldgv_t *ldgvp;
252678453a8Sspeer nxge_ldv_t *ldvp;
253678453a8Sspeer
254678453a8Sspeer int first, limit, vector;
255678453a8Sspeer
256678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
257678453a8Sspeer "==> nxge_intr_vec_find(%cDC %d)",
258678453a8Sspeer type == VP_BOUND_TX ? 'T' : 'R', channel));
259678453a8Sspeer
260678453a8Sspeer if (nxge->ldgvp == 0) {
261678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
262678453a8Sspeer "nxge_hio_intr_vec_find(%cDC %d): ldgvp == 0",
263678453a8Sspeer type == VP_BOUND_TX ? 'T' : 'R', channel));
264678453a8Sspeer return (-1);
265678453a8Sspeer }
266678453a8Sspeer
267678453a8Sspeer hardware = &nxge->pt_config.hw_config;
268678453a8Sspeer
269678453a8Sspeer first = hardware->ldg_chn_start;
270678453a8Sspeer if (type == VP_BOUND_TX) {
271678453a8Sspeer first += 8; /* HIOXXX N2/NIU hack */
272678453a8Sspeer limit = first + hardware->tdc.count;
273678453a8Sspeer } else {
274678453a8Sspeer limit = first + hardware->max_rdcs;
275678453a8Sspeer }
276678453a8Sspeer
277678453a8Sspeer ldgvp = nxge->ldgvp;
278678453a8Sspeer for (vector = first; vector < limit; vector++) {
279678453a8Sspeer ldvp = &ldgvp->ldvp[vector];
280678453a8Sspeer if (ldvp->channel == channel)
281678453a8Sspeer break;
282678453a8Sspeer }
283678453a8Sspeer
284678453a8Sspeer if (vector == limit) {
285678453a8Sspeer return (-1);
286678453a8Sspeer }
287678453a8Sspeer
288678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_vec_find"));
289678453a8Sspeer
290678453a8Sspeer return (vector);
291678453a8Sspeer }
292678453a8Sspeer
293678453a8Sspeer /*
294678453a8Sspeer * ---------------------------------------------------------------------
295678453a8Sspeer * HIO-specific interrupt functions.
296678453a8Sspeer * ---------------------------------------------------------------------
297678453a8Sspeer */
298678453a8Sspeer
299678453a8Sspeer /*
300678453a8Sspeer * nxge_hio_intr_add
301678453a8Sspeer *
302678453a8Sspeer * Add <channel>'s interrupt.
303678453a8Sspeer *
304678453a8Sspeer * Arguments:
305678453a8Sspeer * nxge
306678453a8Sspeer * type Tx or Rx
307678453a8Sspeer * channel The channel whose interrupt we want to remove.
308678453a8Sspeer *
309678453a8Sspeer * Notes:
310678453a8Sspeer *
311678453a8Sspeer * Context:
312678453a8Sspeer * Guest domain
313678453a8Sspeer *
314678453a8Sspeer */
315678453a8Sspeer nxge_status_t
nxge_hio_intr_add(nxge_t * nxge,vpc_type_t type,int channel)316678453a8Sspeer nxge_hio_intr_add(
317678453a8Sspeer nxge_t *nxge,
318678453a8Sspeer vpc_type_t type,
319678453a8Sspeer int channel)
320678453a8Sspeer {
321678453a8Sspeer nxge_hio_dc_t *dc; /* The relevant DMA channel data structure. */
322678453a8Sspeer nxge_intr_t *interrupts; /* The global interrupt data. */
323678453a8Sspeer nxge_ldg_t *group; /* The logical device group data. */
324678453a8Sspeer uint_t *inthandler; /* A parameter to ddi_intr_add_handler */
325678453a8Sspeer
326678453a8Sspeer int vector; /* A shorthand variable */
327678453a8Sspeer int ddi_status; /* The response to ddi_intr_add_handler */
328678453a8Sspeer
329678453a8Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R');
330678453a8Sspeer
331678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
332678453a8Sspeer "==> nxge_hio_intr_add(%cDC %d)", c, channel));
333678453a8Sspeer
334678453a8Sspeer if (nxge->ldgvp == 0) {
335678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
336678453a8Sspeer "nxge_hio_intr_add(%cDC %d): ldgvp == 0", c, channel));
337678453a8Sspeer return (NXGE_ERROR);
338678453a8Sspeer }
339678453a8Sspeer
340678453a8Sspeer if ((dc = nxge_grp_dc_find(nxge, type, channel)) == 0) {
341678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
342678453a8Sspeer "nxge_hio_intr_add: find(%s, %d) failed", c, channel));
343678453a8Sspeer return (NXGE_ERROR);
344678453a8Sspeer }
345678453a8Sspeer
346678453a8Sspeer /* 'nxge_intr_type' is a bad name for this data structure. */
347678453a8Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
348678453a8Sspeer
349678453a8Sspeer /* Set <vector> here to make the following code easier to read. */
350678453a8Sspeer vector = dc->ldg.vector;
351678453a8Sspeer
352678453a8Sspeer group = &nxge->ldgvp->ldgp[vector];
353678453a8Sspeer
354678453a8Sspeer if (group->nldvs == 1) {
355678453a8Sspeer inthandler = (uint_t *)group->ldvp->ldv_intr_handler;
356678453a8Sspeer } else if (group->nldvs > 1) {
357678453a8Sspeer inthandler = (uint_t *)group->sys_intr_handler;
358678453a8Sspeer }
359678453a8Sspeer
360678453a8Sspeer if ((ddi_status = ddi_intr_add_handler(interrupts->htable[vector],
361678453a8Sspeer (ddi_intr_handler_t *)inthandler, group->ldvp, nxge))
362678453a8Sspeer != DDI_SUCCESS) {
363678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
364678453a8Sspeer "nxge_hio_intr_add(%cDC %d): "
365678453a8Sspeer "ddi_intr_add_handler(%d) returned %s",
366678453a8Sspeer c, channel, vector, nxge_ddi_perror(ddi_status)));
367678453a8Sspeer return (NXGE_ERROR);
368678453a8Sspeer }
369678453a8Sspeer
370678453a8Sspeer interrupts->intr_added++;
371678453a8Sspeer
372678453a8Sspeer /* Enable the interrupt. */
373678453a8Sspeer if ((ddi_status = ddi_intr_enable(interrupts->htable[vector]))
374678453a8Sspeer != DDI_SUCCESS) {
375678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
376678453a8Sspeer "nxge_hio_intr_add(%cDC %d): "
377678453a8Sspeer "ddi_intr_enable(%d) returned %s",
378678453a8Sspeer c, channel, vector, nxge_ddi_perror(ddi_status)));
379678453a8Sspeer return (NXGE_ERROR);
380678453a8Sspeer }
381678453a8Sspeer
382678453a8Sspeer interrupts->intr_enabled = B_TRUE;
383678453a8Sspeer
384e759c33aSMichael Speer /*
385e759c33aSMichael Speer * Note: RDC interrupts will be armed in nxge_m_start(). This
386e759c33aSMichael Speer * prevents us from getting an interrupt before we are ready
387e759c33aSMichael Speer * to process packets.
388e759c33aSMichael Speer */
389e759c33aSMichael Speer if (type == VP_BOUND_TX) {
390678453a8Sspeer nxge_hio_ldgimgn(nxge, group);
391e759c33aSMichael Speer }
392678453a8Sspeer
393678453a8Sspeer dc->interrupting = B_TRUE;
394678453a8Sspeer
395678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_add"));
396678453a8Sspeer
397678453a8Sspeer return (NXGE_OK);
398678453a8Sspeer }
399678453a8Sspeer
400678453a8Sspeer /*
401678453a8Sspeer * nxge_hio_intr_remove
402678453a8Sspeer *
403678453a8Sspeer * Remove <channel>'s interrupt.
404678453a8Sspeer *
405678453a8Sspeer * Arguments:
406678453a8Sspeer * nxge
407678453a8Sspeer * type Tx or Rx
408678453a8Sspeer * channel The channel whose interrupt we want to remove.
409678453a8Sspeer *
410678453a8Sspeer * Notes:
411678453a8Sspeer *
412678453a8Sspeer * Context:
413678453a8Sspeer * Guest domain
414678453a8Sspeer *
415678453a8Sspeer */
416678453a8Sspeer nxge_status_t
nxge_hio_intr_remove(nxge_t * nxge,vpc_type_t type,int channel)417678453a8Sspeer nxge_hio_intr_remove(
418678453a8Sspeer nxge_t *nxge,
419678453a8Sspeer vpc_type_t type,
420678453a8Sspeer int channel)
421678453a8Sspeer {
422678453a8Sspeer nxge_hio_dc_t *dc; /* The relevant DMA channel data structure. */
423678453a8Sspeer nxge_intr_t *interrupts; /* The global interrupt data. */
424678453a8Sspeer nxge_ldg_t *group; /* The logical device group data. */
425678453a8Sspeer
426678453a8Sspeer int vector; /* A shorthand variable */
427678453a8Sspeer int status1, status2;
428678453a8Sspeer
429678453a8Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R');
430678453a8Sspeer
431678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
432678453a8Sspeer "==> nxge_hio_intr_remove(%cDC %d)", c, channel));
433678453a8Sspeer
434678453a8Sspeer if (nxge->ldgvp == 0) {
435678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
436678453a8Sspeer "nxge_hio_intr_remove(%cDC %d): ldgvp == 0", c, channel));
437678453a8Sspeer return (NXGE_ERROR);
438678453a8Sspeer }
439678453a8Sspeer
440678453a8Sspeer if ((dc = nxge_grp_dc_find(nxge, type, channel)) == 0) {
441678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
442678453a8Sspeer "nxge_hio_intr_remove(%cDC %d): DC FIND failed",
443678453a8Sspeer c, channel));
444678453a8Sspeer return (NXGE_ERROR);
445678453a8Sspeer }
446678453a8Sspeer
447678453a8Sspeer if (dc->interrupting == B_FALSE) {
448678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
449678453a8Sspeer "nxge_hio_intr_remove(%cDC %d): interrupting == FALSE",
450678453a8Sspeer c, channel));
451678453a8Sspeer return (NXGE_OK);
452678453a8Sspeer }
453678453a8Sspeer
454678453a8Sspeer /* 'nxge_intr_type' is a bad name for this data structure. */
455678453a8Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
456678453a8Sspeer
457678453a8Sspeer /* Set <vector> here to make the following code easier to read. */
458678453a8Sspeer vector = dc->ldg.vector;
459678453a8Sspeer
460678453a8Sspeer group = &nxge->ldgvp->ldgp[vector];
461678453a8Sspeer
462678453a8Sspeer /* Disarm the interrupt. */
463678453a8Sspeer group->arm = B_FALSE;
464678453a8Sspeer nxge_hio_ldgimgn(nxge, group);
465678453a8Sspeer group->arm = B_TRUE; /* HIOXXX There IS a better way */
466678453a8Sspeer
467678453a8Sspeer status1 = DDI_SUCCESS;
468678453a8Sspeer
469678453a8Sspeer /* Disable the interrupt. */
470678453a8Sspeer if ((status2 = ddi_intr_disable(interrupts->htable[vector]))
471678453a8Sspeer != DDI_SUCCESS) {
472678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
473678453a8Sspeer "nxge_hio_intr_remove(%cDC %d): "
474678453a8Sspeer "ddi_intr_disable(%d) returned %s",
475678453a8Sspeer c, channel, vector, nxge_ddi_perror(status2)));
476678453a8Sspeer status1 += status2;
477678453a8Sspeer }
478678453a8Sspeer
479678453a8Sspeer /* Remove the interrupt handler. */
480678453a8Sspeer if ((status2 = ddi_intr_remove_handler(interrupts->htable[vector]))
481678453a8Sspeer != DDI_SUCCESS) {
482678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
483678453a8Sspeer "nxge_hio_intr_remove(%cDC %d): "
484678453a8Sspeer "ddi_intr_remove_handle(%d) returned %s",
485678453a8Sspeer c, channel, vector, nxge_ddi_perror(status2)));
486678453a8Sspeer status1 += status2;
487678453a8Sspeer }
488678453a8Sspeer
489678453a8Sspeer if (status1 == DDI_SUCCESS) {
490678453a8Sspeer dc->interrupting = B_FALSE;
491678453a8Sspeer
492678453a8Sspeer interrupts->intr_added--;
493678453a8Sspeer if (interrupts->intr_added == 0)
494678453a8Sspeer interrupts->intr_enabled = B_FALSE;
495678453a8Sspeer }
496678453a8Sspeer
497678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_remove"));
498678453a8Sspeer
499678453a8Sspeer return (NXGE_OK);
500678453a8Sspeer }
501678453a8Sspeer
502678453a8Sspeer /*
503678453a8Sspeer * nxge_hio_intr_init
504678453a8Sspeer *
505678453a8Sspeer * Initialize interrupts in a guest domain.
506678453a8Sspeer *
507678453a8Sspeer * Arguments:
508678453a8Sspeer * nxge
509678453a8Sspeer *
510678453a8Sspeer * Notes:
511678453a8Sspeer *
512678453a8Sspeer * Context:
513678453a8Sspeer * Guest domain
514678453a8Sspeer *
515678453a8Sspeer */
516678453a8Sspeer nxge_status_t
nxge_hio_intr_init(nxge_t * nxge)517678453a8Sspeer nxge_hio_intr_init(
518678453a8Sspeer nxge_t *nxge)
519678453a8Sspeer {
520678453a8Sspeer int *prop_val;
521678453a8Sspeer uint_t prop_len;
522678453a8Sspeer
523678453a8Sspeer nxge_intr_t *interrupts;
524678453a8Sspeer
525678453a8Sspeer int intr_type, behavior;
526678453a8Sspeer int nintrs, navail, nactual;
527678453a8Sspeer int inum = 0;
528678453a8Sspeer int ddi_status = DDI_SUCCESS;
529678453a8Sspeer
530678453a8Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
531678453a8Sspeer int i;
532678453a8Sspeer
533678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_intr_init"));
534678453a8Sspeer
535678453a8Sspeer /* Look up the "interrupts" property. */
536678453a8Sspeer if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, nxge->dip, 0,
537678453a8Sspeer "interrupts", &prop_val, &prop_len)) != DDI_PROP_SUCCESS) {
538678453a8Sspeer NXGE_ERROR_MSG((nxge, HIO_CTL,
539678453a8Sspeer "==> nxge_hio_intr_init(obp): no 'interrupts' property"));
540678453a8Sspeer return (NXGE_ERROR);
541678453a8Sspeer }
542678453a8Sspeer
543678453a8Sspeer /*
544678453a8Sspeer * For each device assigned, the content of each interrupts
545678453a8Sspeer * property is its logical device group.
546678453a8Sspeer *
547678453a8Sspeer * Assignment of interrupts property is in the the following
548678453a8Sspeer * order:
549678453a8Sspeer *
550678453a8Sspeer * two receive channels
551678453a8Sspeer * two transmit channels
552678453a8Sspeer */
553678453a8Sspeer for (i = 0; i < prop_len; i++) {
554678453a8Sspeer hardware->ldg[i] = prop_val[i];
555678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
556678453a8Sspeer "==> nxge_hio_intr_init(obp): F%d: interrupt #%d, ldg %d",
557678453a8Sspeer nxge->function_num, i, hardware->ldg[i]));
558678453a8Sspeer }
559678453a8Sspeer ddi_prop_free(prop_val);
560678453a8Sspeer
561678453a8Sspeer hardware->max_grpids = prop_len;
562678453a8Sspeer hardware->max_ldgs = prop_len;
563678453a8Sspeer hardware->ldg_chn_start = 0;
564678453a8Sspeer
565678453a8Sspeer /* ----------------------------------------------------- */
566678453a8Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
567678453a8Sspeer
568678453a8Sspeer interrupts->intr_registered = B_FALSE;
569678453a8Sspeer interrupts->intr_enabled = B_FALSE;
570678453a8Sspeer interrupts->start_inum = 0;
571678453a8Sspeer
572678453a8Sspeer ddi_status = ddi_intr_get_supported_types(
573678453a8Sspeer nxge->dip, &interrupts->intr_types);
574678453a8Sspeer if (ddi_status != DDI_SUCCESS) {
575678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
576678453a8Sspeer "ddi_intr_get_supported_types() returned 0x%x, "
577678453a8Sspeer "types = 0x%x", ddi_status, interrupts->intr_types));
578678453a8Sspeer return (NXGE_ERROR);
579678453a8Sspeer }
580678453a8Sspeer
581678453a8Sspeer NXGE_ERROR_MSG((nxge, HIO_CTL, "ddi_intr_get_supported_types() "
582678453a8Sspeer "returned 0x%x, types = 0x%x", ddi_status, interrupts->intr_types));
583678453a8Sspeer
584678453a8Sspeer /* HIOXXX hack */
585678453a8Sspeer interrupts->intr_type = DDI_INTR_TYPE_FIXED;
586678453a8Sspeer /* HIOXXX hack */
587678453a8Sspeer
588678453a8Sspeer intr_type = interrupts->intr_type;
589678453a8Sspeer
590678453a8Sspeer ddi_status = ddi_intr_get_navail(nxge->dip, intr_type, &navail);
591678453a8Sspeer if (ddi_status != DDI_SUCCESS) {
592678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
593678453a8Sspeer "ddi_intr_get_navail() returned %s, navail: %d",
594678453a8Sspeer ddi_status == DDI_FAILURE ? "DDI_FAILURE" :
595678453a8Sspeer "DDI_INTR_NOTFOUND", navail));
596678453a8Sspeer return (NXGE_ERROR);
597678453a8Sspeer }
598678453a8Sspeer
599678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
600678453a8Sspeer "nxge_hio_intr_init: number of available interrupts: %d", navail));
601678453a8Sspeer
602678453a8Sspeer ddi_status = ddi_intr_get_nintrs(nxge->dip, intr_type, &nintrs);
603678453a8Sspeer if (ddi_status != DDI_SUCCESS) {
604678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
605678453a8Sspeer "ddi_intr_get_nintrs() returned %s, nintrs: %d",
606678453a8Sspeer ddi_status == DDI_FAILURE ? "DDI_FAILURE" :
607678453a8Sspeer "DDI_INTR_NOTFOUND", nintrs));
608678453a8Sspeer return (NXGE_ERROR);
609678453a8Sspeer }
610678453a8Sspeer
611678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
612678453a8Sspeer "nxge_hio_intr_init: number of interrupts: %d", nintrs));
613678453a8Sspeer
614678453a8Sspeer interrupts->intr_size = navail * sizeof (ddi_intr_handle_t);
615678453a8Sspeer interrupts->htable = kmem_alloc(interrupts->intr_size, KM_SLEEP);
616678453a8Sspeer
617678453a8Sspeer /*
618678453a8Sspeer * When <behavior> is set to DDI_INTR_ALLOC_STRICT,
619678453a8Sspeer * ddi_intr_alloc() succeeds if and only if <navail>
620678453a8Sspeer * interrupts are are allocated. Otherwise, it fails.
621678453a8Sspeer */
622678453a8Sspeer behavior = ((intr_type == DDI_INTR_TYPE_FIXED) ?
623678453a8Sspeer DDI_INTR_ALLOC_STRICT : DDI_INTR_ALLOC_NORMAL);
624678453a8Sspeer
625678453a8Sspeer ddi_status = ddi_intr_alloc(nxge->dip, interrupts->htable, intr_type,
626678453a8Sspeer inum, navail, &nactual, behavior);
627678453a8Sspeer if (ddi_status != DDI_SUCCESS) {
628678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
629678453a8Sspeer "ddi_intr_alloc() returned 0x%x%, "
630678453a8Sspeer "number allocated: %d", ddi_status, nactual));
631678453a8Sspeer return (NXGE_ERROR);
632678453a8Sspeer }
633678453a8Sspeer
634678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
635678453a8Sspeer "nxge_hio_intr_init: number of interrupts allocated: %d", nactual));
636678453a8Sspeer
637678453a8Sspeer /* <ninterrupts> is a dead variable: we may as well use it. */
638678453a8Sspeer hardware->ninterrupts = nactual;
639678453a8Sspeer
640678453a8Sspeer /* FOI: Get the interrupt priority. */
641678453a8Sspeer if ((ddi_status = ddi_intr_get_pri(interrupts->htable[0],
642678453a8Sspeer (uint_t *)&interrupts->pri)) != DDI_SUCCESS) {
643678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
644678453a8Sspeer " ddi_intr_get_pri() failed: %d", ddi_status));
645678453a8Sspeer }
646678453a8Sspeer
647678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
648678453a8Sspeer "nxge_hio_intr_init: interrupt priority: %d", interrupts->pri));
649678453a8Sspeer
650678453a8Sspeer /* FOI: Get our interrupt capability flags. */
651678453a8Sspeer if ((ddi_status = ddi_intr_get_cap(interrupts->htable[0],
652678453a8Sspeer &interrupts->intr_cap)) != DDI_SUCCESS) {
653678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
654678453a8Sspeer "ddi_intr_get_cap() failed: %d", ddi_status));
655678453a8Sspeer }
656678453a8Sspeer
657678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
658678453a8Sspeer "nxge_hio_intr_init: interrupt capabilities: %d",
659678453a8Sspeer interrupts->intr_cap));
660678453a8Sspeer
661678453a8Sspeer interrupts->intr_registered = B_TRUE;
662678453a8Sspeer
663678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_init"));
664678453a8Sspeer
665678453a8Sspeer return (NXGE_OK);
666678453a8Sspeer }
667678453a8Sspeer
668678453a8Sspeer /*
669678453a8Sspeer * nxge_hio_intr_uninit
670678453a8Sspeer *
671678453a8Sspeer * Uninitialize interrupts in a guest domain.
672678453a8Sspeer *
673678453a8Sspeer * Arguments:
674678453a8Sspeer * nxge
675678453a8Sspeer *
676678453a8Sspeer * Notes:
677678453a8Sspeer *
678678453a8Sspeer * Context:
679678453a8Sspeer * Guest domain
680678453a8Sspeer */
681678453a8Sspeer void
nxge_hio_intr_uninit(nxge_t * nxge)682678453a8Sspeer nxge_hio_intr_uninit(
683678453a8Sspeer nxge_t *nxge)
684678453a8Sspeer {
685678453a8Sspeer nxge_hw_pt_cfg_t *hardware;
686678453a8Sspeer nxge_intr_t *interrupts;
687678453a8Sspeer nxge_ldgv_t *control;
688678453a8Sspeer int i;
689678453a8Sspeer
690678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_intr_uninit"));
691678453a8Sspeer
692678453a8Sspeer /* ----------------------------------------------------- */
693678453a8Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
694678453a8Sspeer
695678453a8Sspeer /*
696678453a8Sspeer * If necessary, disable any currently active interrupts.
697678453a8Sspeer */
698678453a8Sspeer if (interrupts->intr_enabled) {
699678453a8Sspeer nxge_grp_set_t *set;
700678453a8Sspeer nxge_grp_t *group;
701678453a8Sspeer int channel;
702678453a8Sspeer
703678453a8Sspeer set = &nxge->tx_set;
704678453a8Sspeer group = set->group[0]; /* Assumption: only one group! */
705678453a8Sspeer for (channel = 0; channel < NXGE_MAX_TDCS; channel++) {
706678453a8Sspeer if ((1 << channel) & group->map) {
707678453a8Sspeer (void) nxge_hio_intr_remove(
708678453a8Sspeer nxge, VP_BOUND_TX, channel);
709678453a8Sspeer }
710678453a8Sspeer }
711678453a8Sspeer
712678453a8Sspeer set = &nxge->rx_set;
713678453a8Sspeer group = set->group[0]; /* Assumption: only one group! */
714678453a8Sspeer for (channel = 0; channel < NXGE_MAX_RDCS; channel++) {
715678453a8Sspeer if ((1 << channel) & group->map) {
716678453a8Sspeer (void) nxge_hio_intr_remove(
717678453a8Sspeer nxge, VP_BOUND_RX, channel);
718678453a8Sspeer }
719678453a8Sspeer }
720678453a8Sspeer }
721678453a8Sspeer
722678453a8Sspeer /*
723678453a8Sspeer * Free all of our allocated interrupts.
724678453a8Sspeer */
725678453a8Sspeer hardware = &nxge->pt_config.hw_config;
726678453a8Sspeer for (i = 0; i < hardware->ninterrupts; i++) {
727678453a8Sspeer if (interrupts->htable[i])
728678453a8Sspeer (void) ddi_intr_free(interrupts->htable[i]);
729678453a8Sspeer interrupts->htable[i] = 0;
730678453a8Sspeer }
731678453a8Sspeer
732678453a8Sspeer interrupts->intr_registered = B_FALSE;
73348056c53SMichael Speer KMEM_FREE(interrupts->htable, interrupts->intr_size);
73448056c53SMichael Speer interrupts->htable = NULL;
735678453a8Sspeer
7369d5b8bc5SMichael Speer if (nxge->ldgvp == NULL)
7379d5b8bc5SMichael Speer goto nxge_hio_intr_uninit_exit;
7389d5b8bc5SMichael Speer
739678453a8Sspeer control = nxge->ldgvp;
740678453a8Sspeer if (control->ldgp) {
741678453a8Sspeer KMEM_FREE(control->ldgp,
742678453a8Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS);
743678453a8Sspeer control->ldgp = 0;
744678453a8Sspeer }
745678453a8Sspeer
746678453a8Sspeer if (control->ldvp) {
747678453a8Sspeer KMEM_FREE(control->ldvp,
748678453a8Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS);
749678453a8Sspeer control->ldvp = 0;
750678453a8Sspeer }
751678453a8Sspeer
75248056c53SMichael Speer KMEM_FREE(control, sizeof (nxge_ldgv_t));
75348056c53SMichael Speer nxge->ldgvp = NULL;
75448056c53SMichael Speer
7559d5b8bc5SMichael Speer nxge_hio_intr_uninit_exit:
756678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_uninit"));
757678453a8Sspeer }
758678453a8Sspeer
759678453a8Sspeer /*
760678453a8Sspeer * nxge_hio_tdsv_add
761678453a8Sspeer *
762678453a8Sspeer * Add a transmit device interrupt.
763678453a8Sspeer *
764678453a8Sspeer * Arguments:
765678453a8Sspeer * nxge
766678453a8Sspeer * dc The TDC whose interrupt we're adding
767678453a8Sspeer *
768678453a8Sspeer * Notes:
769678453a8Sspeer *
770678453a8Sspeer * Context:
771678453a8Sspeer * Guest domain
772678453a8Sspeer */
773678453a8Sspeer static
774678453a8Sspeer hv_rv_t
nxge_hio_tdsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)775678453a8Sspeer nxge_hio_tdsv_add(
776678453a8Sspeer nxge_t *nxge,
777678453a8Sspeer nxge_hio_dc_t *dc)
778678453a8Sspeer {
779678453a8Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio;
780678453a8Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
781678453a8Sspeer nxhv_dc_fp_t *tx = &nhd->hio.tx;
782678453a8Sspeer hv_rv_t hv_rv;
783678453a8Sspeer
784678453a8Sspeer if (tx->getinfo == 0) {
785678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
786678453a8Sspeer "nx_hio_tdsv_add: tx->getinfo absent"));
787678453a8Sspeer return (EINVAL);
788678453a8Sspeer }
789678453a8Sspeer
790678453a8Sspeer /*
791678453a8Sspeer * Get the dma channel information.
792678453a8Sspeer */
793678453a8Sspeer hv_rv = (*tx->getinfo)(dc->cookie, dc->page, &dc->ldg.index,
794678453a8Sspeer &dc->ldg.ldsv);
795678453a8Sspeer if (hv_rv != 0) {
796678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
797678453a8Sspeer "nx_hio_tdsv_add: tx->getinfo failed: %ld", hv_rv));
798678453a8Sspeer return (EIO);
799678453a8Sspeer }
800678453a8Sspeer
801678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
802678453a8Sspeer "nx_hio_tdsv_add: VRgroup = %d, LDSV = %d",
803678453a8Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv));
804678453a8Sspeer
805678453a8Sspeer if (hardware->tdc.count == 0) {
806678453a8Sspeer hardware->tdc.start = dc->channel;
807678453a8Sspeer }
808678453a8Sspeer
809678453a8Sspeer hardware->tdc.count++;
810678453a8Sspeer hardware->tdc.owned++;
811678453a8Sspeer
812678453a8Sspeer /*
813678453a8Sspeer * In version 1.0 of the hybrid I/O driver, there
814678453a8Sspeer * are eight interrupt vectors per VR.
815678453a8Sspeer *
816678453a8Sspeer * Vectors 0 - 3 are reserved for RDCs.
817678453a8Sspeer * Vectors 4 - 7 are reserved for TDCs.
818678453a8Sspeer */
819678453a8Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2) + HIO_INTR_BLOCK_SIZE;
820678453a8Sspeer // Version 1.0 hack only!
821678453a8Sspeer
822678453a8Sspeer return (0);
823678453a8Sspeer }
824678453a8Sspeer
825678453a8Sspeer /*
826678453a8Sspeer * nxge_hio_rdsv_add
827678453a8Sspeer *
828678453a8Sspeer * Add a transmit device interrupt.
829678453a8Sspeer *
830678453a8Sspeer * Arguments:
831678453a8Sspeer * nxge
832678453a8Sspeer * dc The RDC whose interrupt we're adding
833678453a8Sspeer *
834678453a8Sspeer * Notes:
835678453a8Sspeer *
836678453a8Sspeer * Context:
837678453a8Sspeer * Guest domain
838678453a8Sspeer */
839678453a8Sspeer static
840678453a8Sspeer hv_rv_t
nxge_hio_rdsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)841678453a8Sspeer nxge_hio_rdsv_add(
842678453a8Sspeer nxge_t *nxge,
843678453a8Sspeer nxge_hio_dc_t *dc)
844678453a8Sspeer {
845678453a8Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio;
846678453a8Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
847678453a8Sspeer nxhv_dc_fp_t *rx = &nhd->hio.rx;
848678453a8Sspeer hv_rv_t hv_rv;
849678453a8Sspeer
850678453a8Sspeer if (rx->getinfo == 0) {
851678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
852678453a8Sspeer "nx_hio_tdsv_add: rx->getinfo absent"));
853678453a8Sspeer return (EINVAL);
854678453a8Sspeer }
855678453a8Sspeer
856678453a8Sspeer /*
857678453a8Sspeer * Get DMA channel information.
858678453a8Sspeer */
859678453a8Sspeer hv_rv = (*rx->getinfo)(dc->cookie, dc->page, &dc->ldg.index,
860678453a8Sspeer &dc->ldg.ldsv);
861678453a8Sspeer if (hv_rv != 0) {
862678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
863678453a8Sspeer "nx_hio_tdsv_add: rx->getinfo failed: %ld", hv_rv));
864678453a8Sspeer return (EIO);
865678453a8Sspeer }
866678453a8Sspeer
867678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
868678453a8Sspeer "nx_hio_rdsv_add: VRgroup = %d, LDSV = %d",
869678453a8Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv));
870678453a8Sspeer
871678453a8Sspeer if (hardware->max_rdcs == 0) {
872678453a8Sspeer hardware->start_rdc = dc->channel;
873678453a8Sspeer hardware->def_rdc = dc->channel;
874678453a8Sspeer }
875678453a8Sspeer
876678453a8Sspeer hardware->max_rdcs++;
877678453a8Sspeer
878678453a8Sspeer /*
879678453a8Sspeer * In version 1.0 of the hybrid I/O driver, there
880678453a8Sspeer * are eight interrupt vectors per VR.
881678453a8Sspeer *
882678453a8Sspeer * Vectors 0 - 3 are reserved for RDCs.
883678453a8Sspeer */
884678453a8Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2);
885678453a8Sspeer // Version 1.0 hack only!
886678453a8Sspeer
887678453a8Sspeer return (0);
888678453a8Sspeer }
889678453a8Sspeer
890678453a8Sspeer /*
891678453a8Sspeer * nxge_hio_ldsv_add
892678453a8Sspeer *
893678453a8Sspeer * Add a transmit or receive interrupt.
894678453a8Sspeer *
895678453a8Sspeer * Arguments:
896678453a8Sspeer * nxge
897678453a8Sspeer * dc The DMA channel whose interrupt we're adding
898678453a8Sspeer *
899678453a8Sspeer * Notes:
900678453a8Sspeer * Guest domains can only add interrupts for DMA channels.
901678453a8Sspeer * They cannot access the MAC, MIF, or SYSERR interrupts.
902678453a8Sspeer *
903678453a8Sspeer * Context:
904678453a8Sspeer * Guest domain
905678453a8Sspeer */
906*0dc2366fSVenugopal Iyer int
nxge_hio_ldsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)907*0dc2366fSVenugopal Iyer nxge_hio_ldsv_add(nxge_t *nxge, nxge_hio_dc_t *dc)
908678453a8Sspeer {
909678453a8Sspeer nxge_ldgv_t *control;
910678453a8Sspeer nxge_ldg_t *group;
911678453a8Sspeer nxge_ldv_t *device;
912678453a8Sspeer
913678453a8Sspeer if (dc->type == VP_BOUND_TX) {
914678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(TDC %d)",
915678453a8Sspeer dc->channel));
916*0dc2366fSVenugopal Iyer if (nxge_hio_tdsv_add(nxge, dc) != 0)
917*0dc2366fSVenugopal Iyer return (EIO);
918678453a8Sspeer } else {
919678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(RDC %d)",
920678453a8Sspeer dc->channel));
921*0dc2366fSVenugopal Iyer if (nxge_hio_rdsv_add(nxge, dc) != 0)
922*0dc2366fSVenugopal Iyer return (EIO);
923678453a8Sspeer }
924678453a8Sspeer
925678453a8Sspeer dc->ldg.map |= (1 << dc->ldg.ldsv);
926678453a8Sspeer
927678453a8Sspeer control = nxge->ldgvp;
928678453a8Sspeer if (control == NULL) {
929678453a8Sspeer control = KMEM_ZALLOC(sizeof (nxge_ldgv_t), KM_SLEEP);
930678453a8Sspeer nxge->ldgvp = control;
931678453a8Sspeer control->maxldgs = 1;
932678453a8Sspeer control->maxldvs = 1;
933678453a8Sspeer control->ldgp = KMEM_ZALLOC(
934678453a8Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS, KM_SLEEP);
935678453a8Sspeer control->ldvp = KMEM_ZALLOC(
936678453a8Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS, KM_SLEEP);
937678453a8Sspeer } else {
938678453a8Sspeer control->maxldgs++;
939678453a8Sspeer control->maxldvs++;
940678453a8Sspeer }
941678453a8Sspeer
942678453a8Sspeer /*
943678453a8Sspeer * Initialize the logical device group data structure first.
944678453a8Sspeer */
945678453a8Sspeer group = &control->ldgp[dc->ldg.vector];
946678453a8Sspeer
947678453a8Sspeer (void) memset(group, 0, sizeof (*group));
948678453a8Sspeer
949678453a8Sspeer /*
950678453a8Sspeer * <hw_config.ldg> is a copy of the "interrupts" property.
951678453a8Sspeer */
952678453a8Sspeer group->ldg = nxge->pt_config.hw_config.ldg[dc->ldg.vector];
953678453a8Sspeer group->vldg_index = (uint8_t)dc->ldg.index;
954678453a8Sspeer /*
955678453a8Sspeer * Since <vldg_index> is a dead variable, I'm reusing
956678453a8Sspeer * it in Hybrid I/O to calculate the offset into the
957678453a8Sspeer * virtual PIO_LDSV space.
958678453a8Sspeer */
959678453a8Sspeer
960678453a8Sspeer group->arm = B_TRUE;
961678453a8Sspeer group->ldg_timer = NXGE_TIMER_LDG;
962678453a8Sspeer group->func = nxge->function_num;
963678453a8Sspeer group->vector = dc->ldg.vector;
964678453a8Sspeer /*
965678453a8Sspeer * <intdata> appears to be a dead variable.
966678453a8Sspeer * Though it is not used anywhere in the driver,
967678453a8Sspeer * we'll set it anyway.
968678453a8Sspeer */
969678453a8Sspeer group->intdata = SID_DATA(group->func, group->vector);
970678453a8Sspeer
971678453a8Sspeer group->sys_intr_handler = nxge_intr; /* HIOXXX Does this work? */
972678453a8Sspeer group->nxgep = nxge;
973678453a8Sspeer
974678453a8Sspeer /*
975678453a8Sspeer * Initialize the logical device state vector next.
976678453a8Sspeer */
977678453a8Sspeer device = &control->ldvp[dc->ldg.ldsv];
978678453a8Sspeer
979678453a8Sspeer device->ldg_assigned = group->ldg;
980678453a8Sspeer device->ldv = dc->ldg.ldsv;
981678453a8Sspeer
982678453a8Sspeer if (dc->type == VP_BOUND_TX) {
983678453a8Sspeer device->is_txdma = B_TRUE;
984678453a8Sspeer device->is_rxdma = B_FALSE;
985678453a8Sspeer device->ldv_intr_handler = nxge_tx_intr;
986678453a8Sspeer } else {
987678453a8Sspeer device->is_rxdma = B_TRUE;
988678453a8Sspeer device->is_txdma = B_FALSE;
989678453a8Sspeer device->ldv_intr_handler = nxge_rx_intr;
990678453a8Sspeer }
991678453a8Sspeer device->is_mif = B_FALSE;
992678453a8Sspeer device->is_mac = B_FALSE;
993678453a8Sspeer device->is_syserr = B_FALSE;
994678453a8Sspeer device->use_timer = B_FALSE; /* Set to B_TRUE for syserr only. */
995678453a8Sspeer
996678453a8Sspeer device->channel = dc->channel;
997678453a8Sspeer device->vdma_index = dc->page;
998678453a8Sspeer device->func = nxge->function_num;
999678453a8Sspeer device->ldgp = group;
1000678453a8Sspeer device->ldv_flags = 0;
1001678453a8Sspeer device->ldv_ldf_masks = 0;
1002678453a8Sspeer
1003678453a8Sspeer device->nxgep = nxge;
1004678453a8Sspeer
1005678453a8Sspeer /*
1006678453a8Sspeer * This code seems to imply a strict 1-to-1 correspondence.
1007678453a8Sspeer */
1008678453a8Sspeer group->nldvs++;
1009678453a8Sspeer group->ldvp = device;
1010678453a8Sspeer
1011678453a8Sspeer control->nldvs++;
1012678453a8Sspeer control->ldg_intrs++;
1013678453a8Sspeer
1014678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_ldsv_add"));
1015678453a8Sspeer
1016678453a8Sspeer return (0);
1017678453a8Sspeer }
1018678453a8Sspeer
1019678453a8Sspeer /*
1020678453a8Sspeer * nxge_hio_ldsv_im
1021678453a8Sspeer *
1022678453a8Sspeer * Manage a VLDG's interrupts.
1023678453a8Sspeer *
1024678453a8Sspeer * Arguments:
1025678453a8Sspeer * nxge
1026678453a8Sspeer * group The VLDG to manage
1027678453a8Sspeer *
1028678453a8Sspeer * Notes:
1029678453a8Sspeer * There are 8 sets of 4 64-bit registers per VR, 1 per LDG.
1030678453a8Sspeer * That sums to 256 bytes of virtual PIO_LDSV space.
1031678453a8Sspeer *
1032678453a8Sspeer * VLDG0 starts at offset 0,
1033678453a8Sspeer * VLDG1 starts at offset 32, etc.
1034678453a8Sspeer *
1035678453a8Sspeer * Each set consists of 4 registers:
1036678453a8Sspeer * Logical Device State Vector 0. LDSV0
1037678453a8Sspeer * Logical Device State Vector 1. LDSV1
1038678453a8Sspeer * Logical Device State Vector 2. LDSV2
1039678453a8Sspeer * Logical Device Group Interrupt Management. LDGIMGN
1040678453a8Sspeer *
1041678453a8Sspeer * The first three (LDSVx) are read-only. The 4th register is the
1042678453a8Sspeer * LDGIMGN, the LDG Interrupt Management register, which is used to
1043678453a8Sspeer * arm the LDG, or set its timer.
1044678453a8Sspeer *
1045678453a8Sspeer * The offset to write to is calculated as follows:
1046678453a8Sspeer *
1047678453a8Sspeer * 0x2000 + (VLDG << 4) + offset, where:
1048678453a8Sspeer * VDLG is the virtual group, i.e., index of the LDG.
1049678453a8Sspeer * offset is the offset (alignment 8) of the register
1050678453a8Sspeer * to read or write.
1051678453a8Sspeer *
1052678453a8Sspeer * So, for example, if we wanted to arm the first TDC of VRx, we would
1053678453a8Sspeer * calculate the address as:
1054678453a8Sspeer *
1055678453a8Sspeer * 0x2000 + (0 << 4) + 0x18 = 0x18
1056678453a8Sspeer *
1057678453a8Sspeer * Context:
1058678453a8Sspeer * Guest domain
1059678453a8Sspeer *
1060678453a8Sspeer */
1061678453a8Sspeer void
nxge_hio_ldsv_im(nxge_t * nxge,nxge_ldg_t * group,pio_ld_op_t op,uint64_t * value)1062678453a8Sspeer nxge_hio_ldsv_im(
1063678453a8Sspeer /* Read any register in the PIO_LDSV space. */
1064678453a8Sspeer nxge_t *nxge,
1065678453a8Sspeer nxge_ldg_t *group,
1066678453a8Sspeer pio_ld_op_t op,
1067678453a8Sspeer uint64_t *value)
1068678453a8Sspeer {
1069678453a8Sspeer uint64_t offset = VLDG_OFFSET;
1070678453a8Sspeer
1071678453a8Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */
1072678453a8Sspeer offset += (op * sizeof (uint64_t)); /* 0, 8, 16, 24 */
1073678453a8Sspeer
1074678453a8Sspeer NXGE_REG_RD64(nxge->npi_handle, offset, value);
1075678453a8Sspeer }
1076678453a8Sspeer
1077678453a8Sspeer void
nxge_hio_ldgimgn(nxge_t * nxge,nxge_ldg_t * group)1078678453a8Sspeer nxge_hio_ldgimgn(
1079678453a8Sspeer /* Write the PIO_LDGIMGN register. */
1080678453a8Sspeer nxge_t *nxge,
1081678453a8Sspeer nxge_ldg_t *group)
1082678453a8Sspeer {
1083678453a8Sspeer uint64_t offset = VLDG_OFFSET;
1084678453a8Sspeer ldgimgm_t mgm;
1085678453a8Sspeer
1086678453a8Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */
1087678453a8Sspeer offset += (PIO_LDGIMGN * sizeof (uint64_t)); /* 24 */
1088678453a8Sspeer
1089678453a8Sspeer mgm.value = 0;
1090678453a8Sspeer if (group->arm) {
1091678453a8Sspeer mgm.bits.ldw.arm = 1;
1092678453a8Sspeer mgm.bits.ldw.timer = group->ldg_timer;
1093678453a8Sspeer } else {
1094678453a8Sspeer mgm.bits.ldw.arm = 0;
1095678453a8Sspeer mgm.bits.ldw.timer = 0;
1096678453a8Sspeer }
1097678453a8Sspeer NXGE_REG_WR64(nxge->npi_handle, offset, mgm.value);
1098678453a8Sspeer }
1099