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
706678453a8Sspeer set = &nxge->tx_set;
707678453a8Sspeer group = set->group[0]; /* Assumption: only one group! */
708678453a8Sspeer for (channel = 0; channel < NXGE_MAX_TDCS; channel++) {
709678453a8Sspeer if ((1 << channel) & group->map) {
710678453a8Sspeer (void) nxge_hio_intr_remove(
711678453a8Sspeer nxge, VP_BOUND_TX, channel);
712678453a8Sspeer }
713678453a8Sspeer }
714678453a8Sspeer
715678453a8Sspeer set = &nxge->rx_set;
716678453a8Sspeer group = set->group[0]; /* Assumption: only one group! */
717678453a8Sspeer for (channel = 0; channel < NXGE_MAX_RDCS; channel++) {
718678453a8Sspeer if ((1 << channel) & group->map) {
719678453a8Sspeer (void) nxge_hio_intr_remove(
720678453a8Sspeer nxge, VP_BOUND_RX, channel);
721678453a8Sspeer }
722678453a8Sspeer }
723678453a8Sspeer }
724678453a8Sspeer
725678453a8Sspeer /*
726678453a8Sspeer * Free all of our allocated interrupts.
727678453a8Sspeer */
728678453a8Sspeer hardware = &nxge->pt_config.hw_config;
729678453a8Sspeer for (i = 0; i < hardware->ninterrupts; i++) {
730678453a8Sspeer if (interrupts->htable[i])
731678453a8Sspeer (void) ddi_intr_free(interrupts->htable[i]);
732678453a8Sspeer interrupts->htable[i] = 0;
733678453a8Sspeer }
734678453a8Sspeer
735678453a8Sspeer interrupts->intr_registered = B_FALSE;
73648056c53SMichael Speer KMEM_FREE(interrupts->htable, interrupts->intr_size);
73748056c53SMichael Speer interrupts->htable = NULL;
738678453a8Sspeer
7399d5b8bc5SMichael Speer if (nxge->ldgvp == NULL)
7409d5b8bc5SMichael Speer goto nxge_hio_intr_uninit_exit;
7419d5b8bc5SMichael Speer
742678453a8Sspeer control = nxge->ldgvp;
743678453a8Sspeer if (control->ldgp) {
744678453a8Sspeer KMEM_FREE(control->ldgp,
745678453a8Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS);
746678453a8Sspeer control->ldgp = 0;
747678453a8Sspeer }
748678453a8Sspeer
749678453a8Sspeer if (control->ldvp) {
750678453a8Sspeer KMEM_FREE(control->ldvp,
751678453a8Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS);
752678453a8Sspeer control->ldvp = 0;
753678453a8Sspeer }
754678453a8Sspeer
75548056c53SMichael Speer KMEM_FREE(control, sizeof (nxge_ldgv_t));
75648056c53SMichael Speer nxge->ldgvp = NULL;
75748056c53SMichael Speer
7589d5b8bc5SMichael Speer nxge_hio_intr_uninit_exit:
759678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_uninit"));
760678453a8Sspeer }
761678453a8Sspeer
762678453a8Sspeer /*
763678453a8Sspeer * nxge_hio_tdsv_add
764678453a8Sspeer *
765678453a8Sspeer * Add a transmit device interrupt.
766678453a8Sspeer *
767678453a8Sspeer * Arguments:
768678453a8Sspeer * nxge
769678453a8Sspeer * dc The TDC whose interrupt we're adding
770678453a8Sspeer *
771678453a8Sspeer * Notes:
772678453a8Sspeer *
773678453a8Sspeer * Context:
774678453a8Sspeer * Guest domain
775678453a8Sspeer */
776678453a8Sspeer static
777678453a8Sspeer hv_rv_t
nxge_hio_tdsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)778678453a8Sspeer nxge_hio_tdsv_add(
779678453a8Sspeer nxge_t *nxge,
780678453a8Sspeer nxge_hio_dc_t *dc)
781678453a8Sspeer {
782678453a8Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio;
783678453a8Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
784678453a8Sspeer nxhv_dc_fp_t *tx = &nhd->hio.tx;
785678453a8Sspeer hv_rv_t hv_rv;
786678453a8Sspeer
787678453a8Sspeer if (tx->getinfo == 0) {
788678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
789678453a8Sspeer "nx_hio_tdsv_add: tx->getinfo absent"));
790678453a8Sspeer return (EINVAL);
791678453a8Sspeer }
792678453a8Sspeer
793678453a8Sspeer /*
794678453a8Sspeer * Get the dma channel information.
795678453a8Sspeer */
796678453a8Sspeer hv_rv = (*tx->getinfo)(dc->cookie, dc->page, &dc->ldg.index,
797678453a8Sspeer &dc->ldg.ldsv);
798678453a8Sspeer if (hv_rv != 0) {
799678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
800678453a8Sspeer "nx_hio_tdsv_add: tx->getinfo failed: %ld", hv_rv));
801678453a8Sspeer return (EIO);
802678453a8Sspeer }
803678453a8Sspeer
804678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
805678453a8Sspeer "nx_hio_tdsv_add: VRgroup = %d, LDSV = %d",
806678453a8Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv));
807678453a8Sspeer
808678453a8Sspeer if (hardware->tdc.count == 0) {
809678453a8Sspeer hardware->tdc.start = dc->channel;
810678453a8Sspeer }
811678453a8Sspeer
812678453a8Sspeer hardware->tdc.count++;
813678453a8Sspeer hardware->tdc.owned++;
814678453a8Sspeer
815678453a8Sspeer /*
816678453a8Sspeer * In version 1.0 of the hybrid I/O driver, there
817678453a8Sspeer * are eight interrupt vectors per VR.
818678453a8Sspeer *
819678453a8Sspeer * Vectors 0 - 3 are reserved for RDCs.
820678453a8Sspeer * Vectors 4 - 7 are reserved for TDCs.
821678453a8Sspeer */
822678453a8Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2) + HIO_INTR_BLOCK_SIZE;
823678453a8Sspeer // Version 1.0 hack only!
824678453a8Sspeer
825678453a8Sspeer return (0);
826678453a8Sspeer }
827678453a8Sspeer
828678453a8Sspeer /*
829678453a8Sspeer * nxge_hio_rdsv_add
830678453a8Sspeer *
831678453a8Sspeer * Add a transmit device interrupt.
832678453a8Sspeer *
833678453a8Sspeer * Arguments:
834678453a8Sspeer * nxge
835678453a8Sspeer * dc The RDC whose interrupt we're adding
836678453a8Sspeer *
837678453a8Sspeer * Notes:
838678453a8Sspeer *
839678453a8Sspeer * Context:
840678453a8Sspeer * Guest domain
841678453a8Sspeer */
842678453a8Sspeer static
843678453a8Sspeer hv_rv_t
nxge_hio_rdsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)844678453a8Sspeer nxge_hio_rdsv_add(
845678453a8Sspeer nxge_t *nxge,
846678453a8Sspeer nxge_hio_dc_t *dc)
847678453a8Sspeer {
848678453a8Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio;
849678453a8Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
850678453a8Sspeer nxhv_dc_fp_t *rx = &nhd->hio.rx;
851678453a8Sspeer hv_rv_t hv_rv;
852678453a8Sspeer
853678453a8Sspeer if (rx->getinfo == 0) {
854678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
855678453a8Sspeer "nx_hio_tdsv_add: rx->getinfo absent"));
856678453a8Sspeer return (EINVAL);
857678453a8Sspeer }
858678453a8Sspeer
859678453a8Sspeer /*
860678453a8Sspeer * Get DMA channel information.
861678453a8Sspeer */
862678453a8Sspeer hv_rv = (*rx->getinfo)(dc->cookie, dc->page, &dc->ldg.index,
863678453a8Sspeer &dc->ldg.ldsv);
864678453a8Sspeer if (hv_rv != 0) {
865678453a8Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
866678453a8Sspeer "nx_hio_tdsv_add: rx->getinfo failed: %ld", hv_rv));
867678453a8Sspeer return (EIO);
868678453a8Sspeer }
869678453a8Sspeer
870678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
871678453a8Sspeer "nx_hio_rdsv_add: VRgroup = %d, LDSV = %d",
872678453a8Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv));
873678453a8Sspeer
874678453a8Sspeer if (hardware->max_rdcs == 0) {
875678453a8Sspeer hardware->start_rdc = dc->channel;
876678453a8Sspeer hardware->def_rdc = dc->channel;
877678453a8Sspeer }
878678453a8Sspeer
879678453a8Sspeer hardware->max_rdcs++;
880678453a8Sspeer
881678453a8Sspeer /*
882678453a8Sspeer * In version 1.0 of the hybrid I/O driver, there
883678453a8Sspeer * are eight interrupt vectors per VR.
884678453a8Sspeer *
885678453a8Sspeer * Vectors 0 - 3 are reserved for RDCs.
886678453a8Sspeer */
887678453a8Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2);
888678453a8Sspeer // Version 1.0 hack only!
889678453a8Sspeer
890678453a8Sspeer return (0);
891678453a8Sspeer }
892678453a8Sspeer
893678453a8Sspeer /*
894678453a8Sspeer * nxge_hio_ldsv_add
895678453a8Sspeer *
896678453a8Sspeer * Add a transmit or receive interrupt.
897678453a8Sspeer *
898678453a8Sspeer * Arguments:
899678453a8Sspeer * nxge
900678453a8Sspeer * dc The DMA channel whose interrupt we're adding
901678453a8Sspeer *
902678453a8Sspeer * Notes:
903678453a8Sspeer * Guest domains can only add interrupts for DMA channels.
904678453a8Sspeer * They cannot access the MAC, MIF, or SYSERR interrupts.
905678453a8Sspeer *
906678453a8Sspeer * Context:
907678453a8Sspeer * Guest domain
908678453a8Sspeer */
9090dc2366fSVenugopal Iyer int
nxge_hio_ldsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)9100dc2366fSVenugopal Iyer nxge_hio_ldsv_add(nxge_t *nxge, nxge_hio_dc_t *dc)
911678453a8Sspeer {
912678453a8Sspeer nxge_ldgv_t *control;
913678453a8Sspeer nxge_ldg_t *group;
914678453a8Sspeer nxge_ldv_t *device;
915678453a8Sspeer
916678453a8Sspeer if (dc->type == VP_BOUND_TX) {
917678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(TDC %d)",
918678453a8Sspeer dc->channel));
9190dc2366fSVenugopal Iyer if (nxge_hio_tdsv_add(nxge, dc) != 0)
9200dc2366fSVenugopal Iyer return (EIO);
921678453a8Sspeer } else {
922678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(RDC %d)",
923678453a8Sspeer dc->channel));
9240dc2366fSVenugopal Iyer if (nxge_hio_rdsv_add(nxge, dc) != 0)
9250dc2366fSVenugopal Iyer return (EIO);
926678453a8Sspeer }
927678453a8Sspeer
928678453a8Sspeer dc->ldg.map |= (1 << dc->ldg.ldsv);
929678453a8Sspeer
930678453a8Sspeer control = nxge->ldgvp;
931678453a8Sspeer if (control == NULL) {
932678453a8Sspeer control = KMEM_ZALLOC(sizeof (nxge_ldgv_t), KM_SLEEP);
933678453a8Sspeer nxge->ldgvp = control;
934678453a8Sspeer control->maxldgs = 1;
935678453a8Sspeer control->maxldvs = 1;
936678453a8Sspeer control->ldgp = KMEM_ZALLOC(
937678453a8Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS, KM_SLEEP);
938678453a8Sspeer control->ldvp = KMEM_ZALLOC(
939678453a8Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS, KM_SLEEP);
940678453a8Sspeer } else {
941678453a8Sspeer control->maxldgs++;
942678453a8Sspeer control->maxldvs++;
943678453a8Sspeer }
944678453a8Sspeer
945678453a8Sspeer /*
946678453a8Sspeer * Initialize the logical device group data structure first.
947678453a8Sspeer */
948678453a8Sspeer group = &control->ldgp[dc->ldg.vector];
949678453a8Sspeer
950678453a8Sspeer (void) memset(group, 0, sizeof (*group));
951678453a8Sspeer
952678453a8Sspeer /*
953678453a8Sspeer * <hw_config.ldg> is a copy of the "interrupts" property.
954678453a8Sspeer */
955678453a8Sspeer group->ldg = nxge->pt_config.hw_config.ldg[dc->ldg.vector];
956678453a8Sspeer group->vldg_index = (uint8_t)dc->ldg.index;
957678453a8Sspeer /*
958678453a8Sspeer * Since <vldg_index> is a dead variable, I'm reusing
959678453a8Sspeer * it in Hybrid I/O to calculate the offset into the
960678453a8Sspeer * virtual PIO_LDSV space.
961678453a8Sspeer */
962678453a8Sspeer
963678453a8Sspeer group->arm = B_TRUE;
964678453a8Sspeer group->ldg_timer = NXGE_TIMER_LDG;
965678453a8Sspeer group->func = nxge->function_num;
966678453a8Sspeer group->vector = dc->ldg.vector;
967678453a8Sspeer /*
968678453a8Sspeer * <intdata> appears to be a dead variable.
969678453a8Sspeer * Though it is not used anywhere in the driver,
970678453a8Sspeer * we'll set it anyway.
971678453a8Sspeer */
972678453a8Sspeer group->intdata = SID_DATA(group->func, group->vector);
973678453a8Sspeer
974678453a8Sspeer group->sys_intr_handler = nxge_intr; /* HIOXXX Does this work? */
975678453a8Sspeer group->nxgep = nxge;
976678453a8Sspeer
977678453a8Sspeer /*
978678453a8Sspeer * Initialize the logical device state vector next.
979678453a8Sspeer */
980678453a8Sspeer device = &control->ldvp[dc->ldg.ldsv];
981678453a8Sspeer
982678453a8Sspeer device->ldg_assigned = group->ldg;
983678453a8Sspeer device->ldv = dc->ldg.ldsv;
984678453a8Sspeer
985678453a8Sspeer if (dc->type == VP_BOUND_TX) {
986678453a8Sspeer device->is_txdma = B_TRUE;
987678453a8Sspeer device->is_rxdma = B_FALSE;
988678453a8Sspeer device->ldv_intr_handler = nxge_tx_intr;
989678453a8Sspeer } else {
990678453a8Sspeer device->is_rxdma = B_TRUE;
991678453a8Sspeer device->is_txdma = B_FALSE;
992678453a8Sspeer device->ldv_intr_handler = nxge_rx_intr;
993678453a8Sspeer }
994678453a8Sspeer device->is_mif = B_FALSE;
995678453a8Sspeer device->is_mac = B_FALSE;
996678453a8Sspeer device->is_syserr = B_FALSE;
997678453a8Sspeer device->use_timer = B_FALSE; /* Set to B_TRUE for syserr only. */
998678453a8Sspeer
999678453a8Sspeer device->channel = dc->channel;
1000678453a8Sspeer device->vdma_index = dc->page;
1001678453a8Sspeer device->func = nxge->function_num;
1002678453a8Sspeer device->ldgp = group;
1003678453a8Sspeer device->ldv_flags = 0;
1004678453a8Sspeer device->ldv_ldf_masks = 0;
1005678453a8Sspeer
1006678453a8Sspeer device->nxgep = nxge;
1007678453a8Sspeer
1008678453a8Sspeer /*
1009678453a8Sspeer * This code seems to imply a strict 1-to-1 correspondence.
1010678453a8Sspeer */
1011678453a8Sspeer group->nldvs++;
1012678453a8Sspeer group->ldvp = device;
1013678453a8Sspeer
1014678453a8Sspeer control->nldvs++;
1015678453a8Sspeer control->ldg_intrs++;
1016678453a8Sspeer
1017678453a8Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_ldsv_add"));
1018678453a8Sspeer
1019678453a8Sspeer return (0);
1020678453a8Sspeer }
1021678453a8Sspeer
1022678453a8Sspeer /*
1023678453a8Sspeer * nxge_hio_ldsv_im
1024678453a8Sspeer *
1025678453a8Sspeer * Manage a VLDG's interrupts.
1026678453a8Sspeer *
1027678453a8Sspeer * Arguments:
1028678453a8Sspeer * nxge
1029678453a8Sspeer * group The VLDG to manage
1030678453a8Sspeer *
1031678453a8Sspeer * Notes:
1032678453a8Sspeer * There are 8 sets of 4 64-bit registers per VR, 1 per LDG.
1033678453a8Sspeer * That sums to 256 bytes of virtual PIO_LDSV space.
1034678453a8Sspeer *
1035678453a8Sspeer * VLDG0 starts at offset 0,
1036678453a8Sspeer * VLDG1 starts at offset 32, etc.
1037678453a8Sspeer *
1038678453a8Sspeer * Each set consists of 4 registers:
1039678453a8Sspeer * Logical Device State Vector 0. LDSV0
1040678453a8Sspeer * Logical Device State Vector 1. LDSV1
1041678453a8Sspeer * Logical Device State Vector 2. LDSV2
1042678453a8Sspeer * Logical Device Group Interrupt Management. LDGIMGN
1043678453a8Sspeer *
1044678453a8Sspeer * The first three (LDSVx) are read-only. The 4th register is the
1045678453a8Sspeer * LDGIMGN, the LDG Interrupt Management register, which is used to
1046678453a8Sspeer * arm the LDG, or set its timer.
1047678453a8Sspeer *
1048678453a8Sspeer * The offset to write to is calculated as follows:
1049678453a8Sspeer *
1050678453a8Sspeer * 0x2000 + (VLDG << 4) + offset, where:
1051678453a8Sspeer * VDLG is the virtual group, i.e., index of the LDG.
1052678453a8Sspeer * offset is the offset (alignment 8) of the register
1053678453a8Sspeer * to read or write.
1054678453a8Sspeer *
1055678453a8Sspeer * So, for example, if we wanted to arm the first TDC of VRx, we would
1056678453a8Sspeer * calculate the address as:
1057678453a8Sspeer *
1058678453a8Sspeer * 0x2000 + (0 << 4) + 0x18 = 0x18
1059678453a8Sspeer *
1060678453a8Sspeer * Context:
1061678453a8Sspeer * Guest domain
1062678453a8Sspeer *
1063678453a8Sspeer */
1064678453a8Sspeer void
nxge_hio_ldsv_im(nxge_t * nxge,nxge_ldg_t * group,pio_ld_op_t op,uint64_t * value)1065678453a8Sspeer nxge_hio_ldsv_im(
1066678453a8Sspeer /* Read any register in the PIO_LDSV space. */
1067678453a8Sspeer nxge_t *nxge,
1068678453a8Sspeer nxge_ldg_t *group,
1069678453a8Sspeer pio_ld_op_t op,
1070678453a8Sspeer uint64_t *value)
1071678453a8Sspeer {
1072678453a8Sspeer uint64_t offset = VLDG_OFFSET;
1073678453a8Sspeer
1074678453a8Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */
1075678453a8Sspeer offset += (op * sizeof (uint64_t)); /* 0, 8, 16, 24 */
1076678453a8Sspeer
1077678453a8Sspeer NXGE_REG_RD64(nxge->npi_handle, offset, value);
1078678453a8Sspeer }
1079678453a8Sspeer
1080678453a8Sspeer void
nxge_hio_ldgimgn(nxge_t * nxge,nxge_ldg_t * group)1081678453a8Sspeer nxge_hio_ldgimgn(
1082678453a8Sspeer /* Write the PIO_LDGIMGN register. */
1083678453a8Sspeer nxge_t *nxge,
1084678453a8Sspeer nxge_ldg_t *group)
1085678453a8Sspeer {
1086678453a8Sspeer uint64_t offset = VLDG_OFFSET;
1087678453a8Sspeer ldgimgm_t mgm;
1088678453a8Sspeer
1089678453a8Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */
1090678453a8Sspeer offset += (PIO_LDGIMGN * sizeof (uint64_t)); /* 24 */
1091678453a8Sspeer
1092678453a8Sspeer mgm.value = 0;
1093678453a8Sspeer if (group->arm) {
1094678453a8Sspeer mgm.bits.ldw.arm = 1;
1095678453a8Sspeer mgm.bits.ldw.timer = group->ldg_timer;
1096678453a8Sspeer } else {
1097678453a8Sspeer mgm.bits.ldw.arm = 0;
1098678453a8Sspeer mgm.bits.ldw.timer = 0;
1099678453a8Sspeer }
1100678453a8Sspeer NXGE_REG_WR64(nxge->npi_handle, offset, mgm.value);
1101678453a8Sspeer }
1102