16495Sspeer /*
26495Sspeer * CDDL HEADER START
36495Sspeer *
46495Sspeer * The contents of this file are subject to the terms of the
56495Sspeer * Common Development and Distribution License (the "License").
66495Sspeer * You may not use this file except in compliance with the License.
76495Sspeer *
86495Sspeer * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96495Sspeer * or http://www.opensolaris.org/os/licensing.
106495Sspeer * See the License for the specific language governing permissions
116495Sspeer * and limitations under the License.
126495Sspeer *
136495Sspeer * When distributing Covered Code, include this CDDL HEADER in each
146495Sspeer * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156495Sspeer * If applicable, add the following below this CDDL HEADER, with the
166495Sspeer * fields enclosed by brackets "[]" replaced with your own identifying
176495Sspeer * information: Portions Copyright [yyyy] [name of copyright owner]
186495Sspeer *
196495Sspeer * CDDL HEADER END
206495Sspeer */
216495Sspeer
226495Sspeer /*
23*11878SVenu.Iyer@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
246495Sspeer * Use is subject to license terms.
256495Sspeer */
266495Sspeer
276495Sspeer /*
286495Sspeer * nxge_intr.c
296495Sspeer *
306495Sspeer * This file manages the interrupts for a hybrid I/O (hio) device.
316495Sspeer * In the future, it may manage interrupts for all Neptune-based
326495Sspeer * devices.
336495Sspeer *
346495Sspeer */
356495Sspeer
366495Sspeer #include <sys/nxge/nxge_impl.h>
376495Sspeer #include <sys/nxge/nxge_hio.h>
386495Sspeer
396495Sspeer /*
406495Sspeer * External prototypes
416495Sspeer */
426495Sspeer
436495Sspeer /* The following function may be found in nxge_[t|r]xdma.c */
446495Sspeer extern uint_t nxge_tx_intr(void *, void *);
456495Sspeer extern uint_t nxge_rx_intr(void *, void *);
466495Sspeer
476495Sspeer /*
486495Sspeer * Local prototypes
496495Sspeer */
506495Sspeer static int nxge_intr_vec_find(nxge_t *, vpc_type_t, int);
516495Sspeer
526495Sspeer /*
536495Sspeer * nxge_intr_add
546495Sspeer *
556495Sspeer * Add <channel>'s interrupt.
566495Sspeer *
576495Sspeer * Arguments:
586495Sspeer * nxge
596495Sspeer * type Tx or Rx
606495Sspeer * channel The channel whose interrupt we want to add.
616495Sspeer *
626495Sspeer * Notes:
636495Sspeer * Add here means: add a handler, enable, & arm the interrupt.
646495Sspeer *
656495Sspeer * Context:
666495Sspeer * Service domain
676495Sspeer *
686495Sspeer */
696495Sspeer nxge_status_t
nxge_intr_add(nxge_t * nxge,vpc_type_t type,int channel)706495Sspeer nxge_intr_add(
716495Sspeer nxge_t *nxge,
726495Sspeer vpc_type_t type,
736495Sspeer int channel)
746495Sspeer {
756495Sspeer nxge_intr_t *interrupts; /* The global interrupt data. */
766495Sspeer nxge_ldg_t *group; /* The logical device group data. */
776495Sspeer nxge_ldv_t *ldvp;
786495Sspeer
796495Sspeer uint_t *inthandler; /* A parameter to ddi_intr_add_handler */
806495Sspeer int vector;
816495Sspeer int status1, status2;
826495Sspeer
836495Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R');
846495Sspeer
856495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_intr_add"));
866495Sspeer
876495Sspeer if ((vector = nxge_intr_vec_find(nxge, type, channel)) == -1) {
886495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
896495Sspeer "nxge_intr_add(%cDC %d): vector not found", c, channel));
906495Sspeer return (NXGE_ERROR);
916495Sspeer }
926495Sspeer
936495Sspeer ldvp = &nxge->ldgvp->ldvp[vector];
946495Sspeer group = ldvp->ldgp;
956495Sspeer
966495Sspeer if (group->nldvs == 1) {
976495Sspeer inthandler = (uint_t *)group->ldvp->ldv_intr_handler;
986495Sspeer } else if (group->nldvs > 1) {
996495Sspeer inthandler = (uint_t *)group->sys_intr_handler;
1006495Sspeer }
1016495Sspeer
1026495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
1036495Sspeer
1046495Sspeer status1 = DDI_SUCCESS;
1056495Sspeer
1066495Sspeer if ((status2 = ddi_intr_add_handler(interrupts->htable[vector],
1076495Sspeer (ddi_intr_handler_t *)inthandler, group->ldvp, nxge))
1086495Sspeer != DDI_SUCCESS) {
1096495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_add(%cDC %d): "
1106495Sspeer "ddi_intr_add_handler(%d) returned %s",
1116495Sspeer c, channel, vector, nxge_ddi_perror(status2)));
1126495Sspeer status1 += status2;
1136495Sspeer }
1146495Sspeer
1156495Sspeer interrupts->intr_added++;
1166495Sspeer
1176495Sspeer /* Enable the interrupt. */
1186495Sspeer if ((status2 = ddi_intr_enable(interrupts->htable[vector]))
1196495Sspeer != DDI_SUCCESS) {
1206495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_add(%cDC %d): "
1216495Sspeer "ddi_intr_enable(%d) returned %s",
1226495Sspeer c, channel, vector, nxge_ddi_perror(status2)));
1236495Sspeer status1 += status2;
1246495Sspeer }
1256495Sspeer
1266495Sspeer if (status1 == DDI_SUCCESS) {
1276495Sspeer interrupts->intr_enabled = B_TRUE;
1286495Sspeer
1296495Sspeer /* Finally, arm the interrupt. */
1306495Sspeer if (group->nldvs == 1) {
1316495Sspeer npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge);
1326495Sspeer (void) npi_intr_ldg_mgmt_set(handle, group->ldg,
1336495Sspeer B_TRUE, group->ldg_timer);
1346495Sspeer }
1356495Sspeer }
1366495Sspeer
1376495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_add"));
1386495Sspeer
1396495Sspeer return (NXGE_OK);
1406495Sspeer }
1416495Sspeer
1426495Sspeer /*
1436495Sspeer * nxge_intr_remove
1446495Sspeer *
1456495Sspeer * Remove <channel>'s interrupt.
1466495Sspeer *
1476495Sspeer * Arguments:
1486495Sspeer * nxge
1496495Sspeer * type Tx or Rx
1506495Sspeer * channel The channel whose interrupt we want to remove.
1516495Sspeer *
1526495Sspeer * Notes:
1536495Sspeer * Remove here means: disarm, disable, & remove the handler.
1546495Sspeer *
1556495Sspeer * Context:
1566495Sspeer * Service domain
1576495Sspeer *
1586495Sspeer */
1596495Sspeer nxge_status_t
nxge_intr_remove(nxge_t * nxge,vpc_type_t type,int channel)1606495Sspeer nxge_intr_remove(
1616495Sspeer nxge_t *nxge,
1626495Sspeer vpc_type_t type,
1636495Sspeer int channel)
1646495Sspeer {
1656495Sspeer nxge_intr_t *interrupts; /* The global interrupt data. */
1666495Sspeer nxge_ldg_t *group; /* The logical device group data. */
1676495Sspeer nxge_ldv_t *ldvp;
1686495Sspeer
1696495Sspeer int vector;
1706495Sspeer int status1, status2;
1716495Sspeer
1726495Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R');
1736495Sspeer
1746495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_intr_remove"));
1756495Sspeer
1766495Sspeer if ((vector = nxge_intr_vec_find(nxge, type, channel)) == -1) {
1776495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
1786495Sspeer "nxge_intr_remove(%cDC %d): vector not found", c, channel));
1796495Sspeer return (NXGE_ERROR);
1806495Sspeer }
1816495Sspeer
1826495Sspeer ldvp = &nxge->ldgvp->ldvp[vector];
1836495Sspeer group = ldvp->ldgp;
1846495Sspeer
1856495Sspeer /* Disarm the interrupt. */
1866495Sspeer if (group->nldvs == 1) {
1876495Sspeer npi_handle_t handle = NXGE_DEV_NPI_HANDLE(nxge);
1886495Sspeer group->arm = B_FALSE;
1896495Sspeer (void) npi_intr_ldg_mgmt_set(handle, group->ldg,
1906495Sspeer B_TRUE, group->ldg_timer);
1916495Sspeer group->arm = B_TRUE; /* HIOXXX There IS a better way */
1926495Sspeer }
1936495Sspeer
1946495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
1956495Sspeer
1966495Sspeer status1 = DDI_SUCCESS;
1976495Sspeer
1986495Sspeer /* Disable the interrupt. */
1996495Sspeer if ((status2 = ddi_intr_disable(interrupts->htable[vector]))
2006495Sspeer != DDI_SUCCESS) {
2016495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_remove(%cDC %d)"
2026495Sspeer ": ddi_intr_disable(%d) returned %s",
2036495Sspeer c, channel, vector, nxge_ddi_perror(status2)));
2046495Sspeer status1 += status2;
2056495Sspeer }
2066495Sspeer
2076495Sspeer /* Remove the interrupt handler. */
2086495Sspeer if ((status2 = ddi_intr_remove_handler(interrupts->htable[vector]))
2096495Sspeer != DDI_SUCCESS) {
2106495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, "nxge_intr_remove(%cDC %d)"
2116495Sspeer ": ddi_intr_remove_handler(%d) returned %s",
2126495Sspeer c, channel, vector, nxge_ddi_perror(status2)));
2136495Sspeer status1 += status2;
2146495Sspeer }
2156495Sspeer
2166495Sspeer if (status1 == DDI_SUCCESS) {
2176495Sspeer interrupts->intr_added--;
2186495Sspeer if (interrupts->intr_added == 0)
2196495Sspeer interrupts->intr_enabled = B_FALSE;
2206495Sspeer }
2216495Sspeer
2226495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_remove"));
2236495Sspeer
2246495Sspeer return (NXGE_OK);
2256495Sspeer }
2266495Sspeer
2276495Sspeer /*
2286495Sspeer * nxge_intr_vec_find
2296495Sspeer *
2306495Sspeer * Find the interrupt vector associated with <channel>.
2316495Sspeer *
2326495Sspeer * Arguments:
2336495Sspeer * nxge
2346495Sspeer * type Tx or Rx
2356495Sspeer * channel The channel whose vector we want to find.
2366495Sspeer *
2376495Sspeer * Notes:
2386495Sspeer *
2396495Sspeer * Context:
2406495Sspeer * Service domain
2416495Sspeer *
2426495Sspeer */
2436495Sspeer static
2446495Sspeer int
nxge_intr_vec_find(nxge_t * nxge,vpc_type_t type,int channel)2456495Sspeer nxge_intr_vec_find(
2466495Sspeer nxge_t *nxge,
2476495Sspeer vpc_type_t type,
2486495Sspeer int channel)
2496495Sspeer {
2506495Sspeer nxge_hw_pt_cfg_t *hardware;
2516495Sspeer nxge_ldgv_t *ldgvp;
2526495Sspeer nxge_ldv_t *ldvp;
2536495Sspeer
2546495Sspeer int first, limit, vector;
2556495Sspeer
2566495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
2576495Sspeer "==> nxge_intr_vec_find(%cDC %d)",
2586495Sspeer type == VP_BOUND_TX ? 'T' : 'R', channel));
2596495Sspeer
2606495Sspeer if (nxge->ldgvp == 0) {
2616495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
2626495Sspeer "nxge_hio_intr_vec_find(%cDC %d): ldgvp == 0",
2636495Sspeer type == VP_BOUND_TX ? 'T' : 'R', channel));
2646495Sspeer return (-1);
2656495Sspeer }
2666495Sspeer
2676495Sspeer hardware = &nxge->pt_config.hw_config;
2686495Sspeer
2696495Sspeer first = hardware->ldg_chn_start;
2706495Sspeer if (type == VP_BOUND_TX) {
2716495Sspeer first += 8; /* HIOXXX N2/NIU hack */
2726495Sspeer limit = first + hardware->tdc.count;
2736495Sspeer } else {
2746495Sspeer limit = first + hardware->max_rdcs;
2756495Sspeer }
2766495Sspeer
2776495Sspeer ldgvp = nxge->ldgvp;
2786495Sspeer for (vector = first; vector < limit; vector++) {
2796495Sspeer ldvp = &ldgvp->ldvp[vector];
2806495Sspeer if (ldvp->channel == channel)
2816495Sspeer break;
2826495Sspeer }
2836495Sspeer
2846495Sspeer if (vector == limit) {
2856495Sspeer return (-1);
2866495Sspeer }
2876495Sspeer
2886495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_intr_vec_find"));
2896495Sspeer
2906495Sspeer return (vector);
2916495Sspeer }
2926495Sspeer
2936495Sspeer /*
2946495Sspeer * ---------------------------------------------------------------------
2956495Sspeer * HIO-specific interrupt functions.
2966495Sspeer * ---------------------------------------------------------------------
2976495Sspeer */
2986495Sspeer
2996495Sspeer /*
3006495Sspeer * nxge_hio_intr_add
3016495Sspeer *
3026495Sspeer * Add <channel>'s interrupt.
3036495Sspeer *
3046495Sspeer * Arguments:
3056495Sspeer * nxge
3066495Sspeer * type Tx or Rx
3076495Sspeer * channel The channel whose interrupt we want to remove.
3086495Sspeer *
3096495Sspeer * Notes:
3106495Sspeer *
3116495Sspeer * Context:
3126495Sspeer * Guest domain
3136495Sspeer *
3146495Sspeer */
3156495Sspeer nxge_status_t
nxge_hio_intr_add(nxge_t * nxge,vpc_type_t type,int channel)3166495Sspeer nxge_hio_intr_add(
3176495Sspeer nxge_t *nxge,
3186495Sspeer vpc_type_t type,
3196495Sspeer int channel)
3206495Sspeer {
3216495Sspeer nxge_hio_dc_t *dc; /* The relevant DMA channel data structure. */
3226495Sspeer nxge_intr_t *interrupts; /* The global interrupt data. */
3236495Sspeer nxge_ldg_t *group; /* The logical device group data. */
3246495Sspeer uint_t *inthandler; /* A parameter to ddi_intr_add_handler */
3256495Sspeer
3266495Sspeer int vector; /* A shorthand variable */
3276495Sspeer int ddi_status; /* The response to ddi_intr_add_handler */
3286495Sspeer
3296495Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R');
3306495Sspeer
3316495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
3326495Sspeer "==> nxge_hio_intr_add(%cDC %d)", c, channel));
3336495Sspeer
3346495Sspeer if (nxge->ldgvp == 0) {
3356495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
3366495Sspeer "nxge_hio_intr_add(%cDC %d): ldgvp == 0", c, channel));
3376495Sspeer return (NXGE_ERROR);
3386495Sspeer }
3396495Sspeer
3406495Sspeer if ((dc = nxge_grp_dc_find(nxge, type, channel)) == 0) {
3416495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
3426495Sspeer "nxge_hio_intr_add: find(%s, %d) failed", c, channel));
3436495Sspeer return (NXGE_ERROR);
3446495Sspeer }
3456495Sspeer
3466495Sspeer /* 'nxge_intr_type' is a bad name for this data structure. */
3476495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
3486495Sspeer
3496495Sspeer /* Set <vector> here to make the following code easier to read. */
3506495Sspeer vector = dc->ldg.vector;
3516495Sspeer
3526495Sspeer group = &nxge->ldgvp->ldgp[vector];
3536495Sspeer
3546495Sspeer if (group->nldvs == 1) {
3556495Sspeer inthandler = (uint_t *)group->ldvp->ldv_intr_handler;
3566495Sspeer } else if (group->nldvs > 1) {
3576495Sspeer inthandler = (uint_t *)group->sys_intr_handler;
3586495Sspeer }
3596495Sspeer
3606495Sspeer if ((ddi_status = ddi_intr_add_handler(interrupts->htable[vector],
3616495Sspeer (ddi_intr_handler_t *)inthandler, group->ldvp, nxge))
3626495Sspeer != DDI_SUCCESS) {
3636495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
3646495Sspeer "nxge_hio_intr_add(%cDC %d): "
3656495Sspeer "ddi_intr_add_handler(%d) returned %s",
3666495Sspeer c, channel, vector, nxge_ddi_perror(ddi_status)));
3676495Sspeer return (NXGE_ERROR);
3686495Sspeer }
3696495Sspeer
3706495Sspeer interrupts->intr_added++;
3716495Sspeer
3726495Sspeer /* Enable the interrupt. */
3736495Sspeer if ((ddi_status = ddi_intr_enable(interrupts->htable[vector]))
3746495Sspeer != DDI_SUCCESS) {
3756495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
3766495Sspeer "nxge_hio_intr_add(%cDC %d): "
3776495Sspeer "ddi_intr_enable(%d) returned %s",
3786495Sspeer c, channel, vector, nxge_ddi_perror(ddi_status)));
3796495Sspeer return (NXGE_ERROR);
3806495Sspeer }
3816495Sspeer
3826495Sspeer interrupts->intr_enabled = B_TRUE;
3836495Sspeer
3849232SMichael.Speer@Sun.COM /*
3859232SMichael.Speer@Sun.COM * Note: RDC interrupts will be armed in nxge_m_start(). This
3869232SMichael.Speer@Sun.COM * prevents us from getting an interrupt before we are ready
3879232SMichael.Speer@Sun.COM * to process packets.
3889232SMichael.Speer@Sun.COM */
3899232SMichael.Speer@Sun.COM if (type == VP_BOUND_TX) {
3909232SMichael.Speer@Sun.COM nxge_hio_ldgimgn(nxge, group);
3919232SMichael.Speer@Sun.COM }
3926495Sspeer
3936495Sspeer dc->interrupting = B_TRUE;
3946495Sspeer
3956495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_add"));
3966495Sspeer
3976495Sspeer return (NXGE_OK);
3986495Sspeer }
3996495Sspeer
4006495Sspeer /*
4016495Sspeer * nxge_hio_intr_remove
4026495Sspeer *
4036495Sspeer * Remove <channel>'s interrupt.
4046495Sspeer *
4056495Sspeer * Arguments:
4066495Sspeer * nxge
4076495Sspeer * type Tx or Rx
4086495Sspeer * channel The channel whose interrupt we want to remove.
4096495Sspeer *
4106495Sspeer * Notes:
4116495Sspeer *
4126495Sspeer * Context:
4136495Sspeer * Guest domain
4146495Sspeer *
4156495Sspeer */
4166495Sspeer nxge_status_t
nxge_hio_intr_remove(nxge_t * nxge,vpc_type_t type,int channel)4176495Sspeer nxge_hio_intr_remove(
4186495Sspeer nxge_t *nxge,
4196495Sspeer vpc_type_t type,
4206495Sspeer int channel)
4216495Sspeer {
4226495Sspeer nxge_hio_dc_t *dc; /* The relevant DMA channel data structure. */
4236495Sspeer nxge_intr_t *interrupts; /* The global interrupt data. */
4246495Sspeer nxge_ldg_t *group; /* The logical device group data. */
4256495Sspeer
4266495Sspeer int vector; /* A shorthand variable */
4276495Sspeer int status1, status2;
4286495Sspeer
4296495Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R');
4306495Sspeer
4316495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
4326495Sspeer "==> nxge_hio_intr_remove(%cDC %d)", c, channel));
4336495Sspeer
4346495Sspeer if (nxge->ldgvp == 0) {
4356495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
4366495Sspeer "nxge_hio_intr_remove(%cDC %d): ldgvp == 0", c, channel));
4376495Sspeer return (NXGE_ERROR);
4386495Sspeer }
4396495Sspeer
4406495Sspeer if ((dc = nxge_grp_dc_find(nxge, type, channel)) == 0) {
4416495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
4426495Sspeer "nxge_hio_intr_remove(%cDC %d): DC FIND failed",
4436495Sspeer c, channel));
4446495Sspeer return (NXGE_ERROR);
4456495Sspeer }
4466495Sspeer
4476495Sspeer if (dc->interrupting == B_FALSE) {
4486495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
4496495Sspeer "nxge_hio_intr_remove(%cDC %d): interrupting == FALSE",
4506495Sspeer c, channel));
4516495Sspeer return (NXGE_OK);
4526495Sspeer }
4536495Sspeer
4546495Sspeer /* 'nxge_intr_type' is a bad name for this data structure. */
4556495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
4566495Sspeer
4576495Sspeer /* Set <vector> here to make the following code easier to read. */
4586495Sspeer vector = dc->ldg.vector;
4596495Sspeer
4606495Sspeer group = &nxge->ldgvp->ldgp[vector];
4616495Sspeer
4626495Sspeer /* Disarm the interrupt. */
4636495Sspeer group->arm = B_FALSE;
4646495Sspeer nxge_hio_ldgimgn(nxge, group);
4656495Sspeer group->arm = B_TRUE; /* HIOXXX There IS a better way */
4666495Sspeer
4676495Sspeer status1 = DDI_SUCCESS;
4686495Sspeer
4696495Sspeer /* Disable the interrupt. */
4706495Sspeer if ((status2 = ddi_intr_disable(interrupts->htable[vector]))
4716495Sspeer != DDI_SUCCESS) {
4726495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
4736495Sspeer "nxge_hio_intr_remove(%cDC %d): "
4746495Sspeer "ddi_intr_disable(%d) returned %s",
4756495Sspeer c, channel, vector, nxge_ddi_perror(status2)));
4766495Sspeer status1 += status2;
4776495Sspeer }
4786495Sspeer
4796495Sspeer /* Remove the interrupt handler. */
4806495Sspeer if ((status2 = ddi_intr_remove_handler(interrupts->htable[vector]))
4816495Sspeer != DDI_SUCCESS) {
4826495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
4836495Sspeer "nxge_hio_intr_remove(%cDC %d): "
4846495Sspeer "ddi_intr_remove_handle(%d) returned %s",
4856495Sspeer c, channel, vector, nxge_ddi_perror(status2)));
4866495Sspeer status1 += status2;
4876495Sspeer }
4886495Sspeer
4896495Sspeer if (status1 == DDI_SUCCESS) {
4906495Sspeer dc->interrupting = B_FALSE;
4916495Sspeer
4926495Sspeer interrupts->intr_added--;
4936495Sspeer if (interrupts->intr_added == 0)
4946495Sspeer interrupts->intr_enabled = B_FALSE;
4956495Sspeer }
4966495Sspeer
4976495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_remove"));
4986495Sspeer
4996495Sspeer return (NXGE_OK);
5006495Sspeer }
5016495Sspeer
5026495Sspeer /*
5036495Sspeer * nxge_hio_intr_init
5046495Sspeer *
5056495Sspeer * Initialize interrupts in a guest domain.
5066495Sspeer *
5076495Sspeer * Arguments:
5086495Sspeer * nxge
5096495Sspeer *
5106495Sspeer * Notes:
5116495Sspeer *
5126495Sspeer * Context:
5136495Sspeer * Guest domain
5146495Sspeer *
5156495Sspeer */
5166495Sspeer nxge_status_t
nxge_hio_intr_init(nxge_t * nxge)5176495Sspeer nxge_hio_intr_init(
5186495Sspeer nxge_t *nxge)
5196495Sspeer {
5206495Sspeer int *prop_val;
5216495Sspeer uint_t prop_len;
5226495Sspeer
5236495Sspeer nxge_intr_t *interrupts;
5246495Sspeer
5256495Sspeer int intr_type, behavior;
5266495Sspeer int nintrs, navail, nactual;
5276495Sspeer int inum = 0;
5286495Sspeer int ddi_status = DDI_SUCCESS;
5296495Sspeer
5306495Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
5316495Sspeer int i;
5326495Sspeer
5336495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_intr_init"));
5346495Sspeer
5356495Sspeer /* Look up the "interrupts" property. */
5366495Sspeer if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, nxge->dip, 0,
5376495Sspeer "interrupts", &prop_val, &prop_len)) != DDI_PROP_SUCCESS) {
5386495Sspeer NXGE_ERROR_MSG((nxge, HIO_CTL,
5396495Sspeer "==> nxge_hio_intr_init(obp): no 'interrupts' property"));
5406495Sspeer return (NXGE_ERROR);
5416495Sspeer }
5426495Sspeer
5436495Sspeer /*
5446495Sspeer * For each device assigned, the content of each interrupts
5456495Sspeer * property is its logical device group.
5466495Sspeer *
5476495Sspeer * Assignment of interrupts property is in the the following
5486495Sspeer * order:
5496495Sspeer *
5506495Sspeer * two receive channels
5516495Sspeer * two transmit channels
5526495Sspeer */
5536495Sspeer for (i = 0; i < prop_len; i++) {
5546495Sspeer hardware->ldg[i] = prop_val[i];
5556495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
5566495Sspeer "==> nxge_hio_intr_init(obp): F%d: interrupt #%d, ldg %d",
5576495Sspeer nxge->function_num, i, hardware->ldg[i]));
5586495Sspeer }
5596495Sspeer ddi_prop_free(prop_val);
5606495Sspeer
5616495Sspeer hardware->max_grpids = prop_len;
5626495Sspeer hardware->max_ldgs = prop_len;
5636495Sspeer hardware->ldg_chn_start = 0;
5646495Sspeer
5656495Sspeer /* ----------------------------------------------------- */
5666495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
5676495Sspeer
5686495Sspeer interrupts->intr_registered = B_FALSE;
5696495Sspeer interrupts->intr_enabled = B_FALSE;
5706495Sspeer interrupts->start_inum = 0;
5716495Sspeer
5726495Sspeer ddi_status = ddi_intr_get_supported_types(
5736495Sspeer nxge->dip, &interrupts->intr_types);
5746495Sspeer if (ddi_status != DDI_SUCCESS) {
5756495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
5766495Sspeer "ddi_intr_get_supported_types() returned 0x%x, "
5776495Sspeer "types = 0x%x", ddi_status, interrupts->intr_types));
5786495Sspeer return (NXGE_ERROR);
5796495Sspeer }
5806495Sspeer
5816495Sspeer NXGE_ERROR_MSG((nxge, HIO_CTL, "ddi_intr_get_supported_types() "
5826495Sspeer "returned 0x%x, types = 0x%x", ddi_status, interrupts->intr_types));
5836495Sspeer
5846495Sspeer /* HIOXXX hack */
5856495Sspeer interrupts->intr_type = DDI_INTR_TYPE_FIXED;
5866495Sspeer /* HIOXXX hack */
5876495Sspeer
5886495Sspeer intr_type = interrupts->intr_type;
5896495Sspeer
5906495Sspeer ddi_status = ddi_intr_get_navail(nxge->dip, intr_type, &navail);
5916495Sspeer if (ddi_status != DDI_SUCCESS) {
5926495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
5936495Sspeer "ddi_intr_get_navail() returned %s, navail: %d",
5946495Sspeer ddi_status == DDI_FAILURE ? "DDI_FAILURE" :
5956495Sspeer "DDI_INTR_NOTFOUND", navail));
5966495Sspeer return (NXGE_ERROR);
5976495Sspeer }
5986495Sspeer
5996495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
6006495Sspeer "nxge_hio_intr_init: number of available interrupts: %d", navail));
6016495Sspeer
6026495Sspeer ddi_status = ddi_intr_get_nintrs(nxge->dip, intr_type, &nintrs);
6036495Sspeer if (ddi_status != DDI_SUCCESS) {
6046495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
6056495Sspeer "ddi_intr_get_nintrs() returned %s, nintrs: %d",
6066495Sspeer ddi_status == DDI_FAILURE ? "DDI_FAILURE" :
6076495Sspeer "DDI_INTR_NOTFOUND", nintrs));
6086495Sspeer return (NXGE_ERROR);
6096495Sspeer }
6106495Sspeer
6116495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
6126495Sspeer "nxge_hio_intr_init: number of interrupts: %d", nintrs));
6136495Sspeer
6146495Sspeer interrupts->intr_size = navail * sizeof (ddi_intr_handle_t);
6156495Sspeer interrupts->htable = kmem_alloc(interrupts->intr_size, KM_SLEEP);
6166495Sspeer
6176495Sspeer /*
6186495Sspeer * When <behavior> is set to DDI_INTR_ALLOC_STRICT,
6196495Sspeer * ddi_intr_alloc() succeeds if and only if <navail>
6206495Sspeer * interrupts are are allocated. Otherwise, it fails.
6216495Sspeer */
6226495Sspeer behavior = ((intr_type == DDI_INTR_TYPE_FIXED) ?
6236495Sspeer DDI_INTR_ALLOC_STRICT : DDI_INTR_ALLOC_NORMAL);
6246495Sspeer
6256495Sspeer ddi_status = ddi_intr_alloc(nxge->dip, interrupts->htable, intr_type,
6266495Sspeer inum, navail, &nactual, behavior);
6276495Sspeer if (ddi_status != DDI_SUCCESS) {
6286495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
6296495Sspeer "ddi_intr_alloc() returned 0x%x%, "
6306495Sspeer "number allocated: %d", ddi_status, nactual));
6316495Sspeer return (NXGE_ERROR);
6326495Sspeer }
6336495Sspeer
6346495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
6356495Sspeer "nxge_hio_intr_init: number of interrupts allocated: %d", nactual));
6366495Sspeer
6376495Sspeer /* <ninterrupts> is a dead variable: we may as well use it. */
6386495Sspeer hardware->ninterrupts = nactual;
6396495Sspeer
6406495Sspeer /* FOI: Get the interrupt priority. */
6416495Sspeer if ((ddi_status = ddi_intr_get_pri(interrupts->htable[0],
6426495Sspeer (uint_t *)&interrupts->pri)) != DDI_SUCCESS) {
6436495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
6446495Sspeer " ddi_intr_get_pri() failed: %d", ddi_status));
6456495Sspeer }
6466495Sspeer
6476495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
6486495Sspeer "nxge_hio_intr_init: interrupt priority: %d", interrupts->pri));
6496495Sspeer
6506495Sspeer /* FOI: Get our interrupt capability flags. */
6516495Sspeer if ((ddi_status = ddi_intr_get_cap(interrupts->htable[0],
6526495Sspeer &interrupts->intr_cap)) != DDI_SUCCESS) {
6536495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
6546495Sspeer "ddi_intr_get_cap() failed: %d", ddi_status));
6556495Sspeer }
6566495Sspeer
6576495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
6586495Sspeer "nxge_hio_intr_init: interrupt capabilities: %d",
6596495Sspeer interrupts->intr_cap));
6606495Sspeer
6616495Sspeer interrupts->intr_registered = B_TRUE;
6626495Sspeer
6636495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_init"));
6646495Sspeer
6656495Sspeer return (NXGE_OK);
6666495Sspeer }
6676495Sspeer
6686495Sspeer /*
6696495Sspeer * nxge_hio_intr_uninit
6706495Sspeer *
6716495Sspeer * Uninitialize interrupts in a guest domain.
6726495Sspeer *
6736495Sspeer * Arguments:
6746495Sspeer * nxge
6756495Sspeer *
6766495Sspeer * Notes:
6776495Sspeer *
6786495Sspeer * Context:
6796495Sspeer * Guest domain
6806495Sspeer */
6816495Sspeer void
nxge_hio_intr_uninit(nxge_t * nxge)6826495Sspeer nxge_hio_intr_uninit(
6836495Sspeer nxge_t *nxge)
6846495Sspeer {
6856495Sspeer nxge_hw_pt_cfg_t *hardware;
6866495Sspeer nxge_intr_t *interrupts;
6876495Sspeer nxge_ldgv_t *control;
6886495Sspeer int i;
6896495Sspeer
6906495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_intr_uninit"));
6916495Sspeer
6926495Sspeer /* ----------------------------------------------------- */
6936495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type;
6946495Sspeer
6956495Sspeer /*
6966495Sspeer * If necessary, disable any currently active interrupts.
6976495Sspeer */
6986495Sspeer if (interrupts->intr_enabled) {
6996495Sspeer nxge_grp_set_t *set;
7006495Sspeer nxge_grp_t *group;
7016495Sspeer int channel;
7026495Sspeer
7036495Sspeer set = &nxge->tx_set;
7046495Sspeer group = set->group[0]; /* Assumption: only one group! */
7056495Sspeer for (channel = 0; channel < NXGE_MAX_TDCS; channel++) {
7066495Sspeer if ((1 << channel) & group->map) {
7076495Sspeer (void) nxge_hio_intr_remove(
7086495Sspeer nxge, VP_BOUND_TX, channel);
7096495Sspeer }
7106495Sspeer }
7116495Sspeer
7126495Sspeer set = &nxge->rx_set;
7136495Sspeer group = set->group[0]; /* Assumption: only one group! */
7146495Sspeer for (channel = 0; channel < NXGE_MAX_RDCS; channel++) {
7156495Sspeer if ((1 << channel) & group->map) {
7166495Sspeer (void) nxge_hio_intr_remove(
7176495Sspeer nxge, VP_BOUND_RX, channel);
7186495Sspeer }
7196495Sspeer }
7206495Sspeer }
7216495Sspeer
7226495Sspeer /*
7236495Sspeer * Free all of our allocated interrupts.
7246495Sspeer */
7256495Sspeer hardware = &nxge->pt_config.hw_config;
7266495Sspeer for (i = 0; i < hardware->ninterrupts; i++) {
7276495Sspeer if (interrupts->htable[i])
7286495Sspeer (void) ddi_intr_free(interrupts->htable[i]);
7296495Sspeer interrupts->htable[i] = 0;
7306495Sspeer }
7316495Sspeer
7326495Sspeer interrupts->intr_registered = B_FALSE;
7339730SMichael.Speer@Sun.COM KMEM_FREE(interrupts->htable, interrupts->intr_size);
7349730SMichael.Speer@Sun.COM interrupts->htable = NULL;
7356495Sspeer
7367587SMichael.Speer@Sun.COM if (nxge->ldgvp == NULL)
7377587SMichael.Speer@Sun.COM goto nxge_hio_intr_uninit_exit;
7387587SMichael.Speer@Sun.COM
7396495Sspeer control = nxge->ldgvp;
7406495Sspeer if (control->ldgp) {
7416495Sspeer KMEM_FREE(control->ldgp,
7426495Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS);
7436495Sspeer control->ldgp = 0;
7446495Sspeer }
7456495Sspeer
7466495Sspeer if (control->ldvp) {
7476495Sspeer KMEM_FREE(control->ldvp,
7486495Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS);
7496495Sspeer control->ldvp = 0;
7506495Sspeer }
7516495Sspeer
7529730SMichael.Speer@Sun.COM KMEM_FREE(control, sizeof (nxge_ldgv_t));
7539730SMichael.Speer@Sun.COM nxge->ldgvp = NULL;
7549730SMichael.Speer@Sun.COM
7557587SMichael.Speer@Sun.COM nxge_hio_intr_uninit_exit:
7566495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_uninit"));
7576495Sspeer }
7586495Sspeer
7596495Sspeer /*
7606495Sspeer * nxge_hio_tdsv_add
7616495Sspeer *
7626495Sspeer * Add a transmit device interrupt.
7636495Sspeer *
7646495Sspeer * Arguments:
7656495Sspeer * nxge
7666495Sspeer * dc The TDC whose interrupt we're adding
7676495Sspeer *
7686495Sspeer * Notes:
7696495Sspeer *
7706495Sspeer * Context:
7716495Sspeer * Guest domain
7726495Sspeer */
7736495Sspeer static
7746495Sspeer hv_rv_t
nxge_hio_tdsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)7756495Sspeer nxge_hio_tdsv_add(
7766495Sspeer nxge_t *nxge,
7776495Sspeer nxge_hio_dc_t *dc)
7786495Sspeer {
7796495Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio;
7806495Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
7816495Sspeer nxhv_dc_fp_t *tx = &nhd->hio.tx;
7826495Sspeer hv_rv_t hv_rv;
7836495Sspeer
7846495Sspeer if (tx->getinfo == 0) {
7856495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
7866495Sspeer "nx_hio_tdsv_add: tx->getinfo absent"));
7876495Sspeer return (EINVAL);
7886495Sspeer }
7896495Sspeer
7906495Sspeer /*
7916495Sspeer * Get the dma channel information.
7926495Sspeer */
7936495Sspeer hv_rv = (*tx->getinfo)(dc->cookie, dc->page, &dc->ldg.index,
7946495Sspeer &dc->ldg.ldsv);
7956495Sspeer if (hv_rv != 0) {
7966495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
7976495Sspeer "nx_hio_tdsv_add: tx->getinfo failed: %ld", hv_rv));
7986495Sspeer return (EIO);
7996495Sspeer }
8006495Sspeer
8016495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
8026495Sspeer "nx_hio_tdsv_add: VRgroup = %d, LDSV = %d",
8036495Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv));
8046495Sspeer
8056495Sspeer if (hardware->tdc.count == 0) {
8066495Sspeer hardware->tdc.start = dc->channel;
8076495Sspeer }
8086495Sspeer
8096495Sspeer hardware->tdc.count++;
8106495Sspeer hardware->tdc.owned++;
8116495Sspeer
8126495Sspeer /*
8136495Sspeer * In version 1.0 of the hybrid I/O driver, there
8146495Sspeer * are eight interrupt vectors per VR.
8156495Sspeer *
8166495Sspeer * Vectors 0 - 3 are reserved for RDCs.
8176495Sspeer * Vectors 4 - 7 are reserved for TDCs.
8186495Sspeer */
8196495Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2) + HIO_INTR_BLOCK_SIZE;
8206495Sspeer // Version 1.0 hack only!
8216495Sspeer
8226495Sspeer return (0);
8236495Sspeer }
8246495Sspeer
8256495Sspeer /*
8266495Sspeer * nxge_hio_rdsv_add
8276495Sspeer *
8286495Sspeer * Add a transmit device interrupt.
8296495Sspeer *
8306495Sspeer * Arguments:
8316495Sspeer * nxge
8326495Sspeer * dc The RDC whose interrupt we're adding
8336495Sspeer *
8346495Sspeer * Notes:
8356495Sspeer *
8366495Sspeer * Context:
8376495Sspeer * Guest domain
8386495Sspeer */
8396495Sspeer static
8406495Sspeer hv_rv_t
nxge_hio_rdsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)8416495Sspeer nxge_hio_rdsv_add(
8426495Sspeer nxge_t *nxge,
8436495Sspeer nxge_hio_dc_t *dc)
8446495Sspeer {
8456495Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio;
8466495Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config;
8476495Sspeer nxhv_dc_fp_t *rx = &nhd->hio.rx;
8486495Sspeer hv_rv_t hv_rv;
8496495Sspeer
8506495Sspeer if (rx->getinfo == 0) {
8516495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
8526495Sspeer "nx_hio_tdsv_add: rx->getinfo absent"));
8536495Sspeer return (EINVAL);
8546495Sspeer }
8556495Sspeer
8566495Sspeer /*
8576495Sspeer * Get DMA channel information.
8586495Sspeer */
8596495Sspeer hv_rv = (*rx->getinfo)(dc->cookie, dc->page, &dc->ldg.index,
8606495Sspeer &dc->ldg.ldsv);
8616495Sspeer if (hv_rv != 0) {
8626495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL,
8636495Sspeer "nx_hio_tdsv_add: rx->getinfo failed: %ld", hv_rv));
8646495Sspeer return (EIO);
8656495Sspeer }
8666495Sspeer
8676495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL,
8686495Sspeer "nx_hio_rdsv_add: VRgroup = %d, LDSV = %d",
8696495Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv));
8706495Sspeer
8716495Sspeer if (hardware->max_rdcs == 0) {
8726495Sspeer hardware->start_rdc = dc->channel;
8736495Sspeer hardware->def_rdc = dc->channel;
8746495Sspeer }
8756495Sspeer
8766495Sspeer hardware->max_rdcs++;
8776495Sspeer
8786495Sspeer /*
8796495Sspeer * In version 1.0 of the hybrid I/O driver, there
8806495Sspeer * are eight interrupt vectors per VR.
8816495Sspeer *
8826495Sspeer * Vectors 0 - 3 are reserved for RDCs.
8836495Sspeer */
8846495Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2);
8856495Sspeer // Version 1.0 hack only!
8866495Sspeer
8876495Sspeer return (0);
8886495Sspeer }
8896495Sspeer
8906495Sspeer /*
8916495Sspeer * nxge_hio_ldsv_add
8926495Sspeer *
8936495Sspeer * Add a transmit or receive interrupt.
8946495Sspeer *
8956495Sspeer * Arguments:
8966495Sspeer * nxge
8976495Sspeer * dc The DMA channel whose interrupt we're adding
8986495Sspeer *
8996495Sspeer * Notes:
9006495Sspeer * Guest domains can only add interrupts for DMA channels.
9016495Sspeer * They cannot access the MAC, MIF, or SYSERR interrupts.
9026495Sspeer *
9036495Sspeer * Context:
9046495Sspeer * Guest domain
9056495Sspeer */
906*11878SVenu.Iyer@Sun.COM int
nxge_hio_ldsv_add(nxge_t * nxge,nxge_hio_dc_t * dc)907*11878SVenu.Iyer@Sun.COM nxge_hio_ldsv_add(nxge_t *nxge, nxge_hio_dc_t *dc)
9086495Sspeer {
9096495Sspeer nxge_ldgv_t *control;
9106495Sspeer nxge_ldg_t *group;
9116495Sspeer nxge_ldv_t *device;
9126495Sspeer
9136495Sspeer if (dc->type == VP_BOUND_TX) {
9146495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(TDC %d)",
9156495Sspeer dc->channel));
916*11878SVenu.Iyer@Sun.COM if (nxge_hio_tdsv_add(nxge, dc) != 0)
917*11878SVenu.Iyer@Sun.COM return (EIO);
9186495Sspeer } else {
9196495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(RDC %d)",
9206495Sspeer dc->channel));
921*11878SVenu.Iyer@Sun.COM if (nxge_hio_rdsv_add(nxge, dc) != 0)
922*11878SVenu.Iyer@Sun.COM return (EIO);
9236495Sspeer }
9246495Sspeer
9256495Sspeer dc->ldg.map |= (1 << dc->ldg.ldsv);
9266495Sspeer
9276495Sspeer control = nxge->ldgvp;
9286495Sspeer if (control == NULL) {
9296495Sspeer control = KMEM_ZALLOC(sizeof (nxge_ldgv_t), KM_SLEEP);
9306495Sspeer nxge->ldgvp = control;
9316495Sspeer control->maxldgs = 1;
9326495Sspeer control->maxldvs = 1;
9336495Sspeer control->ldgp = KMEM_ZALLOC(
9346495Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS, KM_SLEEP);
9356495Sspeer control->ldvp = KMEM_ZALLOC(
9366495Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS, KM_SLEEP);
9376495Sspeer } else {
9386495Sspeer control->maxldgs++;
9396495Sspeer control->maxldvs++;
9406495Sspeer }
9416495Sspeer
9426495Sspeer /*
9436495Sspeer * Initialize the logical device group data structure first.
9446495Sspeer */
9456495Sspeer group = &control->ldgp[dc->ldg.vector];
9466495Sspeer
9476495Sspeer (void) memset(group, 0, sizeof (*group));
9486495Sspeer
9496495Sspeer /*
9506495Sspeer * <hw_config.ldg> is a copy of the "interrupts" property.
9516495Sspeer */
9526495Sspeer group->ldg = nxge->pt_config.hw_config.ldg[dc->ldg.vector];
9536495Sspeer group->vldg_index = (uint8_t)dc->ldg.index;
9546495Sspeer /*
9556495Sspeer * Since <vldg_index> is a dead variable, I'm reusing
9566495Sspeer * it in Hybrid I/O to calculate the offset into the
9576495Sspeer * virtual PIO_LDSV space.
9586495Sspeer */
9596495Sspeer
9606495Sspeer group->arm = B_TRUE;
9616495Sspeer group->ldg_timer = NXGE_TIMER_LDG;
9626495Sspeer group->func = nxge->function_num;
9636495Sspeer group->vector = dc->ldg.vector;
9646495Sspeer /*
9656495Sspeer * <intdata> appears to be a dead variable.
9666495Sspeer * Though it is not used anywhere in the driver,
9676495Sspeer * we'll set it anyway.
9686495Sspeer */
9696495Sspeer group->intdata = SID_DATA(group->func, group->vector);
9706495Sspeer
9716495Sspeer group->sys_intr_handler = nxge_intr; /* HIOXXX Does this work? */
9726495Sspeer group->nxgep = nxge;
9736495Sspeer
9746495Sspeer /*
9756495Sspeer * Initialize the logical device state vector next.
9766495Sspeer */
9776495Sspeer device = &control->ldvp[dc->ldg.ldsv];
9786495Sspeer
9796495Sspeer device->ldg_assigned = group->ldg;
9806495Sspeer device->ldv = dc->ldg.ldsv;
9816495Sspeer
9826495Sspeer if (dc->type == VP_BOUND_TX) {
9836495Sspeer device->is_txdma = B_TRUE;
9846495Sspeer device->is_rxdma = B_FALSE;
9856495Sspeer device->ldv_intr_handler = nxge_tx_intr;
9866495Sspeer } else {
9876495Sspeer device->is_rxdma = B_TRUE;
9886495Sspeer device->is_txdma = B_FALSE;
9896495Sspeer device->ldv_intr_handler = nxge_rx_intr;
9906495Sspeer }
9916495Sspeer device->is_mif = B_FALSE;
9926495Sspeer device->is_mac = B_FALSE;
9936495Sspeer device->is_syserr = B_FALSE;
9946495Sspeer device->use_timer = B_FALSE; /* Set to B_TRUE for syserr only. */
9956495Sspeer
9966495Sspeer device->channel = dc->channel;
9976495Sspeer device->vdma_index = dc->page;
9986495Sspeer device->func = nxge->function_num;
9996495Sspeer device->ldgp = group;
10006495Sspeer device->ldv_flags = 0;
10016495Sspeer device->ldv_ldf_masks = 0;
10026495Sspeer
10036495Sspeer device->nxgep = nxge;
10046495Sspeer
10056495Sspeer /*
10066495Sspeer * This code seems to imply a strict 1-to-1 correspondence.
10076495Sspeer */
10086495Sspeer group->nldvs++;
10096495Sspeer group->ldvp = device;
10106495Sspeer
10116495Sspeer control->nldvs++;
10126495Sspeer control->ldg_intrs++;
10136495Sspeer
10146495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_ldsv_add"));
10156495Sspeer
10166495Sspeer return (0);
10176495Sspeer }
10186495Sspeer
10196495Sspeer /*
10206495Sspeer * nxge_hio_ldsv_im
10216495Sspeer *
10226495Sspeer * Manage a VLDG's interrupts.
10236495Sspeer *
10246495Sspeer * Arguments:
10256495Sspeer * nxge
10266495Sspeer * group The VLDG to manage
10276495Sspeer *
10286495Sspeer * Notes:
10296495Sspeer * There are 8 sets of 4 64-bit registers per VR, 1 per LDG.
10306495Sspeer * That sums to 256 bytes of virtual PIO_LDSV space.
10316495Sspeer *
10326495Sspeer * VLDG0 starts at offset 0,
10336495Sspeer * VLDG1 starts at offset 32, etc.
10346495Sspeer *
10356495Sspeer * Each set consists of 4 registers:
10366495Sspeer * Logical Device State Vector 0. LDSV0
10376495Sspeer * Logical Device State Vector 1. LDSV1
10386495Sspeer * Logical Device State Vector 2. LDSV2
10396495Sspeer * Logical Device Group Interrupt Management. LDGIMGN
10406495Sspeer *
10416495Sspeer * The first three (LDSVx) are read-only. The 4th register is the
10426495Sspeer * LDGIMGN, the LDG Interrupt Management register, which is used to
10436495Sspeer * arm the LDG, or set its timer.
10446495Sspeer *
10456495Sspeer * The offset to write to is calculated as follows:
10466495Sspeer *
10476495Sspeer * 0x2000 + (VLDG << 4) + offset, where:
10486495Sspeer * VDLG is the virtual group, i.e., index of the LDG.
10496495Sspeer * offset is the offset (alignment 8) of the register
10506495Sspeer * to read or write.
10516495Sspeer *
10526495Sspeer * So, for example, if we wanted to arm the first TDC of VRx, we would
10536495Sspeer * calculate the address as:
10546495Sspeer *
10556495Sspeer * 0x2000 + (0 << 4) + 0x18 = 0x18
10566495Sspeer *
10576495Sspeer * Context:
10586495Sspeer * Guest domain
10596495Sspeer *
10606495Sspeer */
10616495Sspeer void
nxge_hio_ldsv_im(nxge_t * nxge,nxge_ldg_t * group,pio_ld_op_t op,uint64_t * value)10626495Sspeer nxge_hio_ldsv_im(
10636495Sspeer /* Read any register in the PIO_LDSV space. */
10646495Sspeer nxge_t *nxge,
10656495Sspeer nxge_ldg_t *group,
10666495Sspeer pio_ld_op_t op,
10676495Sspeer uint64_t *value)
10686495Sspeer {
10696495Sspeer uint64_t offset = VLDG_OFFSET;
10706495Sspeer
10716495Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */
10726495Sspeer offset += (op * sizeof (uint64_t)); /* 0, 8, 16, 24 */
10736495Sspeer
10746495Sspeer NXGE_REG_RD64(nxge->npi_handle, offset, value);
10756495Sspeer }
10766495Sspeer
10776495Sspeer void
nxge_hio_ldgimgn(nxge_t * nxge,nxge_ldg_t * group)10786495Sspeer nxge_hio_ldgimgn(
10796495Sspeer /* Write the PIO_LDGIMGN register. */
10806495Sspeer nxge_t *nxge,
10816495Sspeer nxge_ldg_t *group)
10826495Sspeer {
10836495Sspeer uint64_t offset = VLDG_OFFSET;
10846495Sspeer ldgimgm_t mgm;
10856495Sspeer
10866495Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */
10876495Sspeer offset += (PIO_LDGIMGN * sizeof (uint64_t)); /* 24 */
10886495Sspeer
10896495Sspeer mgm.value = 0;
10906495Sspeer if (group->arm) {
10916495Sspeer mgm.bits.ldw.arm = 1;
10926495Sspeer mgm.bits.ldw.timer = group->ldg_timer;
10936495Sspeer } else {
10946495Sspeer mgm.bits.ldw.arm = 0;
10956495Sspeer mgm.bits.ldw.timer = 0;
10966495Sspeer }
10976495Sspeer NXGE_REG_WR64(nxge->npi_handle, offset, mgm.value);
10986495Sspeer }
1099