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*9232SMichael.Speer@Sun.COM * Copyright 2009 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 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 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 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 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 384*9232SMichael.Speer@Sun.COM /* 385*9232SMichael.Speer@Sun.COM * Note: RDC interrupts will be armed in nxge_m_start(). This 386*9232SMichael.Speer@Sun.COM * prevents us from getting an interrupt before we are ready 387*9232SMichael.Speer@Sun.COM * to process packets. 388*9232SMichael.Speer@Sun.COM */ 389*9232SMichael.Speer@Sun.COM if (type == VP_BOUND_TX) { 390*9232SMichael.Speer@Sun.COM nxge_hio_ldgimgn(nxge, group); 391*9232SMichael.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 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 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 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; 7336495Sspeer 7347587SMichael.Speer@Sun.COM if (nxge->ldgvp == NULL) 7357587SMichael.Speer@Sun.COM goto nxge_hio_intr_uninit_exit; 7367587SMichael.Speer@Sun.COM 7376495Sspeer control = nxge->ldgvp; 7386495Sspeer if (control->ldgp) { 7396495Sspeer KMEM_FREE(control->ldgp, 7406495Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS); 7416495Sspeer control->ldgp = 0; 7426495Sspeer } 7436495Sspeer 7446495Sspeer if (control->ldvp) { 7456495Sspeer KMEM_FREE(control->ldvp, 7466495Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS); 7476495Sspeer control->ldvp = 0; 7486495Sspeer } 7496495Sspeer 7507587SMichael.Speer@Sun.COM nxge_hio_intr_uninit_exit: 7516495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_uninit")); 7526495Sspeer } 7536495Sspeer 7546495Sspeer /* 7556495Sspeer * nxge_hio_tdsv_add 7566495Sspeer * 7576495Sspeer * Add a transmit device interrupt. 7586495Sspeer * 7596495Sspeer * Arguments: 7606495Sspeer * nxge 7616495Sspeer * dc The TDC whose interrupt we're adding 7626495Sspeer * 7636495Sspeer * Notes: 7646495Sspeer * 7656495Sspeer * Context: 7666495Sspeer * Guest domain 7676495Sspeer */ 7686495Sspeer static 7696495Sspeer hv_rv_t 7706495Sspeer nxge_hio_tdsv_add( 7716495Sspeer nxge_t *nxge, 7726495Sspeer nxge_hio_dc_t *dc) 7736495Sspeer { 7746495Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 7756495Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config; 7766495Sspeer nxhv_dc_fp_t *tx = &nhd->hio.tx; 7776495Sspeer hv_rv_t hv_rv; 7786495Sspeer 7796495Sspeer if (tx->getinfo == 0) { 7806495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 7816495Sspeer "nx_hio_tdsv_add: tx->getinfo absent")); 7826495Sspeer return (EINVAL); 7836495Sspeer } 7846495Sspeer 7856495Sspeer /* 7866495Sspeer * Get the dma channel information. 7876495Sspeer */ 7886495Sspeer hv_rv = (*tx->getinfo)(dc->cookie, dc->page, &dc->ldg.index, 7896495Sspeer &dc->ldg.ldsv); 7906495Sspeer if (hv_rv != 0) { 7916495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 7926495Sspeer "nx_hio_tdsv_add: tx->getinfo failed: %ld", hv_rv)); 7936495Sspeer return (EIO); 7946495Sspeer } 7956495Sspeer 7966495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 7976495Sspeer "nx_hio_tdsv_add: VRgroup = %d, LDSV = %d", 7986495Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv)); 7996495Sspeer 8006495Sspeer if (hardware->tdc.count == 0) { 8016495Sspeer hardware->tdc.start = dc->channel; 8026495Sspeer } 8036495Sspeer 8046495Sspeer hardware->tdc.count++; 8056495Sspeer hardware->tdc.owned++; 8066495Sspeer 8076495Sspeer /* 8086495Sspeer * In version 1.0 of the hybrid I/O driver, there 8096495Sspeer * are eight interrupt vectors per VR. 8106495Sspeer * 8116495Sspeer * Vectors 0 - 3 are reserved for RDCs. 8126495Sspeer * Vectors 4 - 7 are reserved for TDCs. 8136495Sspeer */ 8146495Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2) + HIO_INTR_BLOCK_SIZE; 8156495Sspeer // Version 1.0 hack only! 8166495Sspeer 8176495Sspeer return (0); 8186495Sspeer } 8196495Sspeer 8206495Sspeer /* 8216495Sspeer * nxge_hio_rdsv_add 8226495Sspeer * 8236495Sspeer * Add a transmit device interrupt. 8246495Sspeer * 8256495Sspeer * Arguments: 8266495Sspeer * nxge 8276495Sspeer * dc The RDC whose interrupt we're adding 8286495Sspeer * 8296495Sspeer * Notes: 8306495Sspeer * 8316495Sspeer * Context: 8326495Sspeer * Guest domain 8336495Sspeer */ 8346495Sspeer static 8356495Sspeer hv_rv_t 8366495Sspeer nxge_hio_rdsv_add( 8376495Sspeer nxge_t *nxge, 8386495Sspeer nxge_hio_dc_t *dc) 8396495Sspeer { 8406495Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 8416495Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config; 8426495Sspeer nxhv_dc_fp_t *rx = &nhd->hio.rx; 8436495Sspeer hv_rv_t hv_rv; 8446495Sspeer 8456495Sspeer if (rx->getinfo == 0) { 8466495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 8476495Sspeer "nx_hio_tdsv_add: rx->getinfo absent")); 8486495Sspeer return (EINVAL); 8496495Sspeer } 8506495Sspeer 8516495Sspeer /* 8526495Sspeer * Get DMA channel information. 8536495Sspeer */ 8546495Sspeer hv_rv = (*rx->getinfo)(dc->cookie, dc->page, &dc->ldg.index, 8556495Sspeer &dc->ldg.ldsv); 8566495Sspeer if (hv_rv != 0) { 8576495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 8586495Sspeer "nx_hio_tdsv_add: rx->getinfo failed: %ld", hv_rv)); 8596495Sspeer return (EIO); 8606495Sspeer } 8616495Sspeer 8626495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 8636495Sspeer "nx_hio_rdsv_add: VRgroup = %d, LDSV = %d", 8646495Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv)); 8656495Sspeer 8666495Sspeer if (hardware->max_rdcs == 0) { 8676495Sspeer hardware->start_rdc = dc->channel; 8686495Sspeer hardware->def_rdc = dc->channel; 8696495Sspeer } 8706495Sspeer 8716495Sspeer hardware->max_rdcs++; 8726495Sspeer 8736495Sspeer /* 8746495Sspeer * In version 1.0 of the hybrid I/O driver, there 8756495Sspeer * are eight interrupt vectors per VR. 8766495Sspeer * 8776495Sspeer * Vectors 0 - 3 are reserved for RDCs. 8786495Sspeer */ 8796495Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2); 8806495Sspeer // Version 1.0 hack only! 8816495Sspeer 8826495Sspeer return (0); 8836495Sspeer } 8846495Sspeer 8856495Sspeer /* 8866495Sspeer * nxge_hio_ldsv_add 8876495Sspeer * 8886495Sspeer * Add a transmit or receive interrupt. 8896495Sspeer * 8906495Sspeer * Arguments: 8916495Sspeer * nxge 8926495Sspeer * dc The DMA channel whose interrupt we're adding 8936495Sspeer * 8946495Sspeer * Notes: 8956495Sspeer * Guest domains can only add interrupts for DMA channels. 8966495Sspeer * They cannot access the MAC, MIF, or SYSERR interrupts. 8976495Sspeer * 8986495Sspeer * Context: 8996495Sspeer * Guest domain 9006495Sspeer */ 9016495Sspeer hv_rv_t 9026495Sspeer nxge_hio_ldsv_add( 9036495Sspeer nxge_t *nxge, 9046495Sspeer nxge_hio_dc_t *dc) 9056495Sspeer { 9066495Sspeer nxge_ldgv_t *control; 9076495Sspeer nxge_ldg_t *group; 9086495Sspeer nxge_ldv_t *device; 9096495Sspeer hv_rv_t hv_rv; 9106495Sspeer 9116495Sspeer if (dc->type == VP_BOUND_TX) { 9126495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(TDC %d)", 9136495Sspeer dc->channel)); 9146495Sspeer if ((hv_rv = nxge_hio_tdsv_add(nxge, dc)) != 0) 9156495Sspeer return (hv_rv); 9166495Sspeer } else { 9176495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(RDC %d)", 9186495Sspeer dc->channel)); 9196495Sspeer if ((hv_rv = nxge_hio_rdsv_add(nxge, dc)) != 0) 9206495Sspeer return (hv_rv); 9216495Sspeer } 9226495Sspeer 9236495Sspeer dc->ldg.map |= (1 << dc->ldg.ldsv); 9246495Sspeer 9256495Sspeer control = nxge->ldgvp; 9266495Sspeer if (control == NULL) { 9276495Sspeer control = KMEM_ZALLOC(sizeof (nxge_ldgv_t), KM_SLEEP); 9286495Sspeer nxge->ldgvp = control; 9296495Sspeer control->maxldgs = 1; 9306495Sspeer control->maxldvs = 1; 9316495Sspeer control->ldgp = KMEM_ZALLOC( 9326495Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS, KM_SLEEP); 9336495Sspeer control->ldvp = KMEM_ZALLOC( 9346495Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS, KM_SLEEP); 9356495Sspeer } else { 9366495Sspeer control->maxldgs++; 9376495Sspeer control->maxldvs++; 9386495Sspeer } 9396495Sspeer 9406495Sspeer /* 9416495Sspeer * Initialize the logical device group data structure first. 9426495Sspeer */ 9436495Sspeer group = &control->ldgp[dc->ldg.vector]; 9446495Sspeer 9456495Sspeer (void) memset(group, 0, sizeof (*group)); 9466495Sspeer 9476495Sspeer /* 9486495Sspeer * <hw_config.ldg> is a copy of the "interrupts" property. 9496495Sspeer */ 9506495Sspeer group->ldg = nxge->pt_config.hw_config.ldg[dc->ldg.vector]; 9516495Sspeer group->vldg_index = (uint8_t)dc->ldg.index; 9526495Sspeer /* 9536495Sspeer * Since <vldg_index> is a dead variable, I'm reusing 9546495Sspeer * it in Hybrid I/O to calculate the offset into the 9556495Sspeer * virtual PIO_LDSV space. 9566495Sspeer */ 9576495Sspeer 9586495Sspeer group->arm = B_TRUE; 9596495Sspeer group->ldg_timer = NXGE_TIMER_LDG; 9606495Sspeer group->func = nxge->function_num; 9616495Sspeer group->vector = dc->ldg.vector; 9626495Sspeer /* 9636495Sspeer * <intdata> appears to be a dead variable. 9646495Sspeer * Though it is not used anywhere in the driver, 9656495Sspeer * we'll set it anyway. 9666495Sspeer */ 9676495Sspeer group->intdata = SID_DATA(group->func, group->vector); 9686495Sspeer 9696495Sspeer group->sys_intr_handler = nxge_intr; /* HIOXXX Does this work? */ 9706495Sspeer group->nxgep = nxge; 9716495Sspeer 9726495Sspeer /* 9736495Sspeer * Initialize the logical device state vector next. 9746495Sspeer */ 9756495Sspeer device = &control->ldvp[dc->ldg.ldsv]; 9766495Sspeer 9776495Sspeer device->ldg_assigned = group->ldg; 9786495Sspeer device->ldv = dc->ldg.ldsv; 9796495Sspeer 9806495Sspeer if (dc->type == VP_BOUND_TX) { 9816495Sspeer device->is_txdma = B_TRUE; 9826495Sspeer device->is_rxdma = B_FALSE; 9836495Sspeer device->ldv_intr_handler = nxge_tx_intr; 9846495Sspeer } else { 9856495Sspeer device->is_rxdma = B_TRUE; 9866495Sspeer device->is_txdma = B_FALSE; 9876495Sspeer device->ldv_intr_handler = nxge_rx_intr; 9886495Sspeer } 9896495Sspeer device->is_mif = B_FALSE; 9906495Sspeer device->is_mac = B_FALSE; 9916495Sspeer device->is_syserr = B_FALSE; 9926495Sspeer device->use_timer = B_FALSE; /* Set to B_TRUE for syserr only. */ 9936495Sspeer 9946495Sspeer device->channel = dc->channel; 9956495Sspeer device->vdma_index = dc->page; 9966495Sspeer device->func = nxge->function_num; 9976495Sspeer device->ldgp = group; 9986495Sspeer device->ldv_flags = 0; 9996495Sspeer device->ldv_ldf_masks = 0; 10006495Sspeer 10016495Sspeer device->nxgep = nxge; 10026495Sspeer 10036495Sspeer /* 10046495Sspeer * This code seems to imply a strict 1-to-1 correspondence. 10056495Sspeer */ 10066495Sspeer group->nldvs++; 10076495Sspeer group->ldvp = device; 10086495Sspeer 10096495Sspeer control->nldvs++; 10106495Sspeer control->ldg_intrs++; 10116495Sspeer 10126495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_ldsv_add")); 10136495Sspeer 10146495Sspeer return (0); 10156495Sspeer } 10166495Sspeer 10176495Sspeer /* 10186495Sspeer * nxge_hio_ldsv_im 10196495Sspeer * 10206495Sspeer * Manage a VLDG's interrupts. 10216495Sspeer * 10226495Sspeer * Arguments: 10236495Sspeer * nxge 10246495Sspeer * group The VLDG to manage 10256495Sspeer * 10266495Sspeer * Notes: 10276495Sspeer * There are 8 sets of 4 64-bit registers per VR, 1 per LDG. 10286495Sspeer * That sums to 256 bytes of virtual PIO_LDSV space. 10296495Sspeer * 10306495Sspeer * VLDG0 starts at offset 0, 10316495Sspeer * VLDG1 starts at offset 32, etc. 10326495Sspeer * 10336495Sspeer * Each set consists of 4 registers: 10346495Sspeer * Logical Device State Vector 0. LDSV0 10356495Sspeer * Logical Device State Vector 1. LDSV1 10366495Sspeer * Logical Device State Vector 2. LDSV2 10376495Sspeer * Logical Device Group Interrupt Management. LDGIMGN 10386495Sspeer * 10396495Sspeer * The first three (LDSVx) are read-only. The 4th register is the 10406495Sspeer * LDGIMGN, the LDG Interrupt Management register, which is used to 10416495Sspeer * arm the LDG, or set its timer. 10426495Sspeer * 10436495Sspeer * The offset to write to is calculated as follows: 10446495Sspeer * 10456495Sspeer * 0x2000 + (VLDG << 4) + offset, where: 10466495Sspeer * VDLG is the virtual group, i.e., index of the LDG. 10476495Sspeer * offset is the offset (alignment 8) of the register 10486495Sspeer * to read or write. 10496495Sspeer * 10506495Sspeer * So, for example, if we wanted to arm the first TDC of VRx, we would 10516495Sspeer * calculate the address as: 10526495Sspeer * 10536495Sspeer * 0x2000 + (0 << 4) + 0x18 = 0x18 10546495Sspeer * 10556495Sspeer * Context: 10566495Sspeer * Guest domain 10576495Sspeer * 10586495Sspeer */ 10596495Sspeer void 10606495Sspeer nxge_hio_ldsv_im( 10616495Sspeer /* Read any register in the PIO_LDSV space. */ 10626495Sspeer nxge_t *nxge, 10636495Sspeer nxge_ldg_t *group, 10646495Sspeer pio_ld_op_t op, 10656495Sspeer uint64_t *value) 10666495Sspeer { 10676495Sspeer uint64_t offset = VLDG_OFFSET; 10686495Sspeer 10696495Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */ 10706495Sspeer offset += (op * sizeof (uint64_t)); /* 0, 8, 16, 24 */ 10716495Sspeer 10726495Sspeer NXGE_REG_RD64(nxge->npi_handle, offset, value); 10736495Sspeer } 10746495Sspeer 10756495Sspeer void 10766495Sspeer nxge_hio_ldgimgn( 10776495Sspeer /* Write the PIO_LDGIMGN register. */ 10786495Sspeer nxge_t *nxge, 10796495Sspeer nxge_ldg_t *group) 10806495Sspeer { 10816495Sspeer uint64_t offset = VLDG_OFFSET; 10826495Sspeer ldgimgm_t mgm; 10836495Sspeer 10846495Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */ 10856495Sspeer offset += (PIO_LDGIMGN * sizeof (uint64_t)); /* 24 */ 10866495Sspeer 10876495Sspeer mgm.value = 0; 10886495Sspeer if (group->arm) { 10896495Sspeer mgm.bits.ldw.arm = 1; 10906495Sspeer mgm.bits.ldw.timer = group->ldg_timer; 10916495Sspeer } else { 10926495Sspeer mgm.bits.ldw.arm = 0; 10936495Sspeer mgm.bits.ldw.timer = 0; 10946495Sspeer } 10956495Sspeer NXGE_REG_WR64(nxge->npi_handle, offset, mgm.value); 10966495Sspeer } 1097