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 /* 236495Sspeer * Copyright 2008 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 3846495Sspeer /* Finally, arm the interrupt. */ 3856495Sspeer nxge_hio_ldgimgn(nxge, group); 3866495Sspeer 3876495Sspeer dc->interrupting = B_TRUE; 3886495Sspeer 3896495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_add")); 3906495Sspeer 3916495Sspeer return (NXGE_OK); 3926495Sspeer } 3936495Sspeer 3946495Sspeer /* 3956495Sspeer * nxge_hio_intr_remove 3966495Sspeer * 3976495Sspeer * Remove <channel>'s interrupt. 3986495Sspeer * 3996495Sspeer * Arguments: 4006495Sspeer * nxge 4016495Sspeer * type Tx or Rx 4026495Sspeer * channel The channel whose interrupt we want to remove. 4036495Sspeer * 4046495Sspeer * Notes: 4056495Sspeer * 4066495Sspeer * Context: 4076495Sspeer * Guest domain 4086495Sspeer * 4096495Sspeer */ 4106495Sspeer nxge_status_t 4116495Sspeer nxge_hio_intr_remove( 4126495Sspeer nxge_t *nxge, 4136495Sspeer vpc_type_t type, 4146495Sspeer int channel) 4156495Sspeer { 4166495Sspeer nxge_hio_dc_t *dc; /* The relevant DMA channel data structure. */ 4176495Sspeer nxge_intr_t *interrupts; /* The global interrupt data. */ 4186495Sspeer nxge_ldg_t *group; /* The logical device group data. */ 4196495Sspeer 4206495Sspeer int vector; /* A shorthand variable */ 4216495Sspeer int status1, status2; 4226495Sspeer 4236495Sspeer char c = (type == VP_BOUND_TX ? 'T' : 'R'); 4246495Sspeer 4256495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 4266495Sspeer "==> nxge_hio_intr_remove(%cDC %d)", c, channel)); 4276495Sspeer 4286495Sspeer if (nxge->ldgvp == 0) { 4296495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 4306495Sspeer "nxge_hio_intr_remove(%cDC %d): ldgvp == 0", c, channel)); 4316495Sspeer return (NXGE_ERROR); 4326495Sspeer } 4336495Sspeer 4346495Sspeer if ((dc = nxge_grp_dc_find(nxge, type, channel)) == 0) { 4356495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 4366495Sspeer "nxge_hio_intr_remove(%cDC %d): DC FIND failed", 4376495Sspeer c, channel)); 4386495Sspeer return (NXGE_ERROR); 4396495Sspeer } 4406495Sspeer 4416495Sspeer if (dc->interrupting == B_FALSE) { 4426495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 4436495Sspeer "nxge_hio_intr_remove(%cDC %d): interrupting == FALSE", 4446495Sspeer c, channel)); 4456495Sspeer return (NXGE_OK); 4466495Sspeer } 4476495Sspeer 4486495Sspeer /* 'nxge_intr_type' is a bad name for this data structure. */ 4496495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type; 4506495Sspeer 4516495Sspeer /* Set <vector> here to make the following code easier to read. */ 4526495Sspeer vector = dc->ldg.vector; 4536495Sspeer 4546495Sspeer group = &nxge->ldgvp->ldgp[vector]; 4556495Sspeer 4566495Sspeer /* Disarm the interrupt. */ 4576495Sspeer group->arm = B_FALSE; 4586495Sspeer nxge_hio_ldgimgn(nxge, group); 4596495Sspeer group->arm = B_TRUE; /* HIOXXX There IS a better way */ 4606495Sspeer 4616495Sspeer status1 = DDI_SUCCESS; 4626495Sspeer 4636495Sspeer /* Disable the interrupt. */ 4646495Sspeer if ((status2 = ddi_intr_disable(interrupts->htable[vector])) 4656495Sspeer != DDI_SUCCESS) { 4666495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 4676495Sspeer "nxge_hio_intr_remove(%cDC %d): " 4686495Sspeer "ddi_intr_disable(%d) returned %s", 4696495Sspeer c, channel, vector, nxge_ddi_perror(status2))); 4706495Sspeer status1 += status2; 4716495Sspeer } 4726495Sspeer 4736495Sspeer /* Remove the interrupt handler. */ 4746495Sspeer if ((status2 = ddi_intr_remove_handler(interrupts->htable[vector])) 4756495Sspeer != DDI_SUCCESS) { 4766495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 4776495Sspeer "nxge_hio_intr_remove(%cDC %d): " 4786495Sspeer "ddi_intr_remove_handle(%d) returned %s", 4796495Sspeer c, channel, vector, nxge_ddi_perror(status2))); 4806495Sspeer status1 += status2; 4816495Sspeer } 4826495Sspeer 4836495Sspeer if (status1 == DDI_SUCCESS) { 4846495Sspeer dc->interrupting = B_FALSE; 4856495Sspeer 4866495Sspeer interrupts->intr_added--; 4876495Sspeer if (interrupts->intr_added == 0) 4886495Sspeer interrupts->intr_enabled = B_FALSE; 4896495Sspeer } 4906495Sspeer 4916495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_remove")); 4926495Sspeer 4936495Sspeer return (NXGE_OK); 4946495Sspeer } 4956495Sspeer 4966495Sspeer /* 4976495Sspeer * nxge_hio_intr_init 4986495Sspeer * 4996495Sspeer * Initialize interrupts in a guest domain. 5006495Sspeer * 5016495Sspeer * Arguments: 5026495Sspeer * nxge 5036495Sspeer * 5046495Sspeer * Notes: 5056495Sspeer * 5066495Sspeer * Context: 5076495Sspeer * Guest domain 5086495Sspeer * 5096495Sspeer */ 5106495Sspeer nxge_status_t 5116495Sspeer nxge_hio_intr_init( 5126495Sspeer nxge_t *nxge) 5136495Sspeer { 5146495Sspeer int *prop_val; 5156495Sspeer uint_t prop_len; 5166495Sspeer 5176495Sspeer nxge_intr_t *interrupts; 5186495Sspeer 5196495Sspeer int intr_type, behavior; 5206495Sspeer int nintrs, navail, nactual; 5216495Sspeer int inum = 0; 5226495Sspeer int ddi_status = DDI_SUCCESS; 5236495Sspeer 5246495Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config; 5256495Sspeer int i; 5266495Sspeer 5276495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_intr_init")); 5286495Sspeer 5296495Sspeer /* Look up the "interrupts" property. */ 5306495Sspeer if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, nxge->dip, 0, 5316495Sspeer "interrupts", &prop_val, &prop_len)) != DDI_PROP_SUCCESS) { 5326495Sspeer NXGE_ERROR_MSG((nxge, HIO_CTL, 5336495Sspeer "==> nxge_hio_intr_init(obp): no 'interrupts' property")); 5346495Sspeer return (NXGE_ERROR); 5356495Sspeer } 5366495Sspeer 5376495Sspeer /* 5386495Sspeer * For each device assigned, the content of each interrupts 5396495Sspeer * property is its logical device group. 5406495Sspeer * 5416495Sspeer * Assignment of interrupts property is in the the following 5426495Sspeer * order: 5436495Sspeer * 5446495Sspeer * two receive channels 5456495Sspeer * two transmit channels 5466495Sspeer */ 5476495Sspeer for (i = 0; i < prop_len; i++) { 5486495Sspeer hardware->ldg[i] = prop_val[i]; 5496495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 5506495Sspeer "==> nxge_hio_intr_init(obp): F%d: interrupt #%d, ldg %d", 5516495Sspeer nxge->function_num, i, hardware->ldg[i])); 5526495Sspeer } 5536495Sspeer ddi_prop_free(prop_val); 5546495Sspeer 5556495Sspeer hardware->max_grpids = prop_len; 5566495Sspeer hardware->max_ldgs = prop_len; 5576495Sspeer hardware->ldg_chn_start = 0; 5586495Sspeer 5596495Sspeer /* ----------------------------------------------------- */ 5606495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type; 5616495Sspeer 5626495Sspeer interrupts->intr_registered = B_FALSE; 5636495Sspeer interrupts->intr_enabled = B_FALSE; 5646495Sspeer interrupts->start_inum = 0; 5656495Sspeer 5666495Sspeer ddi_status = ddi_intr_get_supported_types( 5676495Sspeer nxge->dip, &interrupts->intr_types); 5686495Sspeer if (ddi_status != DDI_SUCCESS) { 5696495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 5706495Sspeer "ddi_intr_get_supported_types() returned 0x%x, " 5716495Sspeer "types = 0x%x", ddi_status, interrupts->intr_types)); 5726495Sspeer return (NXGE_ERROR); 5736495Sspeer } 5746495Sspeer 5756495Sspeer NXGE_ERROR_MSG((nxge, HIO_CTL, "ddi_intr_get_supported_types() " 5766495Sspeer "returned 0x%x, types = 0x%x", ddi_status, interrupts->intr_types)); 5776495Sspeer 5786495Sspeer /* HIOXXX hack */ 5796495Sspeer interrupts->intr_type = DDI_INTR_TYPE_FIXED; 5806495Sspeer /* HIOXXX hack */ 5816495Sspeer 5826495Sspeer intr_type = interrupts->intr_type; 5836495Sspeer 5846495Sspeer ddi_status = ddi_intr_get_navail(nxge->dip, intr_type, &navail); 5856495Sspeer if (ddi_status != DDI_SUCCESS) { 5866495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 5876495Sspeer "ddi_intr_get_navail() returned %s, navail: %d", 5886495Sspeer ddi_status == DDI_FAILURE ? "DDI_FAILURE" : 5896495Sspeer "DDI_INTR_NOTFOUND", navail)); 5906495Sspeer return (NXGE_ERROR); 5916495Sspeer } 5926495Sspeer 5936495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 5946495Sspeer "nxge_hio_intr_init: number of available interrupts: %d", navail)); 5956495Sspeer 5966495Sspeer ddi_status = ddi_intr_get_nintrs(nxge->dip, intr_type, &nintrs); 5976495Sspeer if (ddi_status != DDI_SUCCESS) { 5986495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 5996495Sspeer "ddi_intr_get_nintrs() returned %s, nintrs: %d", 6006495Sspeer ddi_status == DDI_FAILURE ? "DDI_FAILURE" : 6016495Sspeer "DDI_INTR_NOTFOUND", nintrs)); 6026495Sspeer return (NXGE_ERROR); 6036495Sspeer } 6046495Sspeer 6056495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 6066495Sspeer "nxge_hio_intr_init: number of interrupts: %d", nintrs)); 6076495Sspeer 6086495Sspeer interrupts->intr_size = navail * sizeof (ddi_intr_handle_t); 6096495Sspeer interrupts->htable = kmem_alloc(interrupts->intr_size, KM_SLEEP); 6106495Sspeer 6116495Sspeer /* 6126495Sspeer * When <behavior> is set to DDI_INTR_ALLOC_STRICT, 6136495Sspeer * ddi_intr_alloc() succeeds if and only if <navail> 6146495Sspeer * interrupts are are allocated. Otherwise, it fails. 6156495Sspeer */ 6166495Sspeer behavior = ((intr_type == DDI_INTR_TYPE_FIXED) ? 6176495Sspeer DDI_INTR_ALLOC_STRICT : DDI_INTR_ALLOC_NORMAL); 6186495Sspeer 6196495Sspeer ddi_status = ddi_intr_alloc(nxge->dip, interrupts->htable, intr_type, 6206495Sspeer inum, navail, &nactual, behavior); 6216495Sspeer if (ddi_status != DDI_SUCCESS) { 6226495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 6236495Sspeer "ddi_intr_alloc() returned 0x%x%, " 6246495Sspeer "number allocated: %d", ddi_status, nactual)); 6256495Sspeer return (NXGE_ERROR); 6266495Sspeer } 6276495Sspeer 6286495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 6296495Sspeer "nxge_hio_intr_init: number of interrupts allocated: %d", nactual)); 6306495Sspeer 6316495Sspeer /* <ninterrupts> is a dead variable: we may as well use it. */ 6326495Sspeer hardware->ninterrupts = nactual; 6336495Sspeer 6346495Sspeer /* FOI: Get the interrupt priority. */ 6356495Sspeer if ((ddi_status = ddi_intr_get_pri(interrupts->htable[0], 6366495Sspeer (uint_t *)&interrupts->pri)) != DDI_SUCCESS) { 6376495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 6386495Sspeer " ddi_intr_get_pri() failed: %d", ddi_status)); 6396495Sspeer } 6406495Sspeer 6416495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 6426495Sspeer "nxge_hio_intr_init: interrupt priority: %d", interrupts->pri)); 6436495Sspeer 6446495Sspeer /* FOI: Get our interrupt capability flags. */ 6456495Sspeer if ((ddi_status = ddi_intr_get_cap(interrupts->htable[0], 6466495Sspeer &interrupts->intr_cap)) != DDI_SUCCESS) { 6476495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 6486495Sspeer "ddi_intr_get_cap() failed: %d", ddi_status)); 6496495Sspeer } 6506495Sspeer 6516495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 6526495Sspeer "nxge_hio_intr_init: interrupt capabilities: %d", 6536495Sspeer interrupts->intr_cap)); 6546495Sspeer 6556495Sspeer interrupts->intr_registered = B_TRUE; 6566495Sspeer 6576495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_init")); 6586495Sspeer 6596495Sspeer return (NXGE_OK); 6606495Sspeer } 6616495Sspeer 6626495Sspeer /* 6636495Sspeer * nxge_hio_intr_uninit 6646495Sspeer * 6656495Sspeer * Uninitialize interrupts in a guest domain. 6666495Sspeer * 6676495Sspeer * Arguments: 6686495Sspeer * nxge 6696495Sspeer * 6706495Sspeer * Notes: 6716495Sspeer * 6726495Sspeer * Context: 6736495Sspeer * Guest domain 6746495Sspeer */ 6756495Sspeer void 6766495Sspeer nxge_hio_intr_uninit( 6776495Sspeer nxge_t *nxge) 6786495Sspeer { 6796495Sspeer nxge_hw_pt_cfg_t *hardware; 6806495Sspeer nxge_intr_t *interrupts; 6816495Sspeer nxge_ldgv_t *control; 6826495Sspeer int i; 6836495Sspeer 6846495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_intr_uninit")); 6856495Sspeer 6866495Sspeer /* ----------------------------------------------------- */ 6876495Sspeer interrupts = (nxge_intr_t *)&nxge->nxge_intr_type; 6886495Sspeer 6896495Sspeer /* 6906495Sspeer * If necessary, disable any currently active interrupts. 6916495Sspeer */ 6926495Sspeer if (interrupts->intr_enabled) { 6936495Sspeer nxge_grp_set_t *set; 6946495Sspeer nxge_grp_t *group; 6956495Sspeer int channel; 6966495Sspeer 6976495Sspeer set = &nxge->tx_set; 6986495Sspeer group = set->group[0]; /* Assumption: only one group! */ 6996495Sspeer for (channel = 0; channel < NXGE_MAX_TDCS; channel++) { 7006495Sspeer if ((1 << channel) & group->map) { 7016495Sspeer (void) nxge_hio_intr_remove( 7026495Sspeer nxge, VP_BOUND_TX, channel); 7036495Sspeer } 7046495Sspeer } 7056495Sspeer 7066495Sspeer set = &nxge->rx_set; 7076495Sspeer group = set->group[0]; /* Assumption: only one group! */ 7086495Sspeer for (channel = 0; channel < NXGE_MAX_RDCS; channel++) { 7096495Sspeer if ((1 << channel) & group->map) { 7106495Sspeer (void) nxge_hio_intr_remove( 7116495Sspeer nxge, VP_BOUND_RX, channel); 7126495Sspeer } 7136495Sspeer } 7146495Sspeer } 7156495Sspeer 7166495Sspeer /* 7176495Sspeer * Free all of our allocated interrupts. 7186495Sspeer */ 7196495Sspeer hardware = &nxge->pt_config.hw_config; 7206495Sspeer for (i = 0; i < hardware->ninterrupts; i++) { 7216495Sspeer if (interrupts->htable[i]) 7226495Sspeer (void) ddi_intr_free(interrupts->htable[i]); 7236495Sspeer interrupts->htable[i] = 0; 7246495Sspeer } 7256495Sspeer 7266495Sspeer interrupts->intr_registered = B_FALSE; 7276495Sspeer 728*7587SMichael.Speer@Sun.COM if (nxge->ldgvp == NULL) 729*7587SMichael.Speer@Sun.COM goto nxge_hio_intr_uninit_exit; 730*7587SMichael.Speer@Sun.COM 7316495Sspeer control = nxge->ldgvp; 7326495Sspeer if (control->ldgp) { 7336495Sspeer KMEM_FREE(control->ldgp, 7346495Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS); 7356495Sspeer control->ldgp = 0; 7366495Sspeer } 7376495Sspeer 7386495Sspeer if (control->ldvp) { 7396495Sspeer KMEM_FREE(control->ldvp, 7406495Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS); 7416495Sspeer control->ldvp = 0; 7426495Sspeer } 7436495Sspeer 744*7587SMichael.Speer@Sun.COM nxge_hio_intr_uninit_exit: 7456495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_intr_uninit")); 7466495Sspeer } 7476495Sspeer 7486495Sspeer /* 7496495Sspeer * nxge_hio_tdsv_add 7506495Sspeer * 7516495Sspeer * Add a transmit device interrupt. 7526495Sspeer * 7536495Sspeer * Arguments: 7546495Sspeer * nxge 7556495Sspeer * dc The TDC whose interrupt we're adding 7566495Sspeer * 7576495Sspeer * Notes: 7586495Sspeer * 7596495Sspeer * Context: 7606495Sspeer * Guest domain 7616495Sspeer */ 7626495Sspeer static 7636495Sspeer hv_rv_t 7646495Sspeer nxge_hio_tdsv_add( 7656495Sspeer nxge_t *nxge, 7666495Sspeer nxge_hio_dc_t *dc) 7676495Sspeer { 7686495Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 7696495Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config; 7706495Sspeer nxhv_dc_fp_t *tx = &nhd->hio.tx; 7716495Sspeer hv_rv_t hv_rv; 7726495Sspeer 7736495Sspeer if (tx->getinfo == 0) { 7746495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 7756495Sspeer "nx_hio_tdsv_add: tx->getinfo absent")); 7766495Sspeer return (EINVAL); 7776495Sspeer } 7786495Sspeer 7796495Sspeer /* 7806495Sspeer * Get the dma channel information. 7816495Sspeer */ 7826495Sspeer hv_rv = (*tx->getinfo)(dc->cookie, dc->page, &dc->ldg.index, 7836495Sspeer &dc->ldg.ldsv); 7846495Sspeer if (hv_rv != 0) { 7856495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 7866495Sspeer "nx_hio_tdsv_add: tx->getinfo failed: %ld", hv_rv)); 7876495Sspeer return (EIO); 7886495Sspeer } 7896495Sspeer 7906495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 7916495Sspeer "nx_hio_tdsv_add: VRgroup = %d, LDSV = %d", 7926495Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv)); 7936495Sspeer 7946495Sspeer if (hardware->tdc.count == 0) { 7956495Sspeer hardware->tdc.start = dc->channel; 7966495Sspeer } 7976495Sspeer 7986495Sspeer hardware->tdc.count++; 7996495Sspeer hardware->tdc.owned++; 8006495Sspeer 8016495Sspeer /* 8026495Sspeer * In version 1.0 of the hybrid I/O driver, there 8036495Sspeer * are eight interrupt vectors per VR. 8046495Sspeer * 8056495Sspeer * Vectors 0 - 3 are reserved for RDCs. 8066495Sspeer * Vectors 4 - 7 are reserved for TDCs. 8076495Sspeer */ 8086495Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2) + HIO_INTR_BLOCK_SIZE; 8096495Sspeer // Version 1.0 hack only! 8106495Sspeer 8116495Sspeer return (0); 8126495Sspeer } 8136495Sspeer 8146495Sspeer /* 8156495Sspeer * nxge_hio_rdsv_add 8166495Sspeer * 8176495Sspeer * Add a transmit device interrupt. 8186495Sspeer * 8196495Sspeer * Arguments: 8206495Sspeer * nxge 8216495Sspeer * dc The RDC whose interrupt we're adding 8226495Sspeer * 8236495Sspeer * Notes: 8246495Sspeer * 8256495Sspeer * Context: 8266495Sspeer * Guest domain 8276495Sspeer */ 8286495Sspeer static 8296495Sspeer hv_rv_t 8306495Sspeer nxge_hio_rdsv_add( 8316495Sspeer nxge_t *nxge, 8326495Sspeer nxge_hio_dc_t *dc) 8336495Sspeer { 8346495Sspeer nxge_hio_data_t *nhd = (nxge_hio_data_t *)nxge->nxge_hw_p->hio; 8356495Sspeer nxge_hw_pt_cfg_t *hardware = &nxge->pt_config.hw_config; 8366495Sspeer nxhv_dc_fp_t *rx = &nhd->hio.rx; 8376495Sspeer hv_rv_t hv_rv; 8386495Sspeer 8396495Sspeer if (rx->getinfo == 0) { 8406495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 8416495Sspeer "nx_hio_tdsv_add: rx->getinfo absent")); 8426495Sspeer return (EINVAL); 8436495Sspeer } 8446495Sspeer 8456495Sspeer /* 8466495Sspeer * Get DMA channel information. 8476495Sspeer */ 8486495Sspeer hv_rv = (*rx->getinfo)(dc->cookie, dc->page, &dc->ldg.index, 8496495Sspeer &dc->ldg.ldsv); 8506495Sspeer if (hv_rv != 0) { 8516495Sspeer NXGE_ERROR_MSG((nxge, NXGE_ERR_CTL, 8526495Sspeer "nx_hio_tdsv_add: rx->getinfo failed: %ld", hv_rv)); 8536495Sspeer return (EIO); 8546495Sspeer } 8556495Sspeer 8566495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, 8576495Sspeer "nx_hio_rdsv_add: VRgroup = %d, LDSV = %d", 8586495Sspeer (int)dc->ldg.index, (int)dc->ldg.ldsv)); 8596495Sspeer 8606495Sspeer if (hardware->max_rdcs == 0) { 8616495Sspeer hardware->start_rdc = dc->channel; 8626495Sspeer hardware->def_rdc = dc->channel; 8636495Sspeer } 8646495Sspeer 8656495Sspeer hardware->max_rdcs++; 8666495Sspeer 8676495Sspeer /* 8686495Sspeer * In version 1.0 of the hybrid I/O driver, there 8696495Sspeer * are eight interrupt vectors per VR. 8706495Sspeer * 8716495Sspeer * Vectors 0 - 3 are reserved for RDCs. 8726495Sspeer */ 8736495Sspeer dc->ldg.vector = (dc->ldg.ldsv % 2); 8746495Sspeer // Version 1.0 hack only! 8756495Sspeer 8766495Sspeer return (0); 8776495Sspeer } 8786495Sspeer 8796495Sspeer /* 8806495Sspeer * nxge_hio_ldsv_add 8816495Sspeer * 8826495Sspeer * Add a transmit or receive interrupt. 8836495Sspeer * 8846495Sspeer * Arguments: 8856495Sspeer * nxge 8866495Sspeer * dc The DMA channel whose interrupt we're adding 8876495Sspeer * 8886495Sspeer * Notes: 8896495Sspeer * Guest domains can only add interrupts for DMA channels. 8906495Sspeer * They cannot access the MAC, MIF, or SYSERR interrupts. 8916495Sspeer * 8926495Sspeer * Context: 8936495Sspeer * Guest domain 8946495Sspeer */ 8956495Sspeer hv_rv_t 8966495Sspeer nxge_hio_ldsv_add( 8976495Sspeer nxge_t *nxge, 8986495Sspeer nxge_hio_dc_t *dc) 8996495Sspeer { 9006495Sspeer nxge_ldgv_t *control; 9016495Sspeer nxge_ldg_t *group; 9026495Sspeer nxge_ldv_t *device; 9036495Sspeer hv_rv_t hv_rv; 9046495Sspeer 9056495Sspeer if (dc->type == VP_BOUND_TX) { 9066495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(TDC %d)", 9076495Sspeer dc->channel)); 9086495Sspeer if ((hv_rv = nxge_hio_tdsv_add(nxge, dc)) != 0) 9096495Sspeer return (hv_rv); 9106495Sspeer } else { 9116495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "==> nxge_hio_ldsv_add(RDC %d)", 9126495Sspeer dc->channel)); 9136495Sspeer if ((hv_rv = nxge_hio_rdsv_add(nxge, dc)) != 0) 9146495Sspeer return (hv_rv); 9156495Sspeer } 9166495Sspeer 9176495Sspeer dc->ldg.map |= (1 << dc->ldg.ldsv); 9186495Sspeer 9196495Sspeer control = nxge->ldgvp; 9206495Sspeer if (control == NULL) { 9216495Sspeer control = KMEM_ZALLOC(sizeof (nxge_ldgv_t), KM_SLEEP); 9226495Sspeer nxge->ldgvp = control; 9236495Sspeer control->maxldgs = 1; 9246495Sspeer control->maxldvs = 1; 9256495Sspeer control->ldgp = KMEM_ZALLOC( 9266495Sspeer sizeof (nxge_ldg_t) * NXGE_INT_MAX_LDGS, KM_SLEEP); 9276495Sspeer control->ldvp = KMEM_ZALLOC( 9286495Sspeer sizeof (nxge_ldv_t) * NXGE_INT_MAX_LDS, KM_SLEEP); 9296495Sspeer } else { 9306495Sspeer control->maxldgs++; 9316495Sspeer control->maxldvs++; 9326495Sspeer } 9336495Sspeer 9346495Sspeer /* 9356495Sspeer * Initialize the logical device group data structure first. 9366495Sspeer */ 9376495Sspeer group = &control->ldgp[dc->ldg.vector]; 9386495Sspeer 9396495Sspeer (void) memset(group, 0, sizeof (*group)); 9406495Sspeer 9416495Sspeer /* 9426495Sspeer * <hw_config.ldg> is a copy of the "interrupts" property. 9436495Sspeer */ 9446495Sspeer group->ldg = nxge->pt_config.hw_config.ldg[dc->ldg.vector]; 9456495Sspeer group->vldg_index = (uint8_t)dc->ldg.index; 9466495Sspeer /* 9476495Sspeer * Since <vldg_index> is a dead variable, I'm reusing 9486495Sspeer * it in Hybrid I/O to calculate the offset into the 9496495Sspeer * virtual PIO_LDSV space. 9506495Sspeer */ 9516495Sspeer 9526495Sspeer group->arm = B_TRUE; 9536495Sspeer group->ldg_timer = NXGE_TIMER_LDG; 9546495Sspeer group->func = nxge->function_num; 9556495Sspeer group->vector = dc->ldg.vector; 9566495Sspeer /* 9576495Sspeer * <intdata> appears to be a dead variable. 9586495Sspeer * Though it is not used anywhere in the driver, 9596495Sspeer * we'll set it anyway. 9606495Sspeer */ 9616495Sspeer group->intdata = SID_DATA(group->func, group->vector); 9626495Sspeer 9636495Sspeer group->sys_intr_handler = nxge_intr; /* HIOXXX Does this work? */ 9646495Sspeer group->nxgep = nxge; 9656495Sspeer 9666495Sspeer /* 9676495Sspeer * Initialize the logical device state vector next. 9686495Sspeer */ 9696495Sspeer device = &control->ldvp[dc->ldg.ldsv]; 9706495Sspeer 9716495Sspeer device->ldg_assigned = group->ldg; 9726495Sspeer device->ldv = dc->ldg.ldsv; 9736495Sspeer 9746495Sspeer if (dc->type == VP_BOUND_TX) { 9756495Sspeer device->is_txdma = B_TRUE; 9766495Sspeer device->is_rxdma = B_FALSE; 9776495Sspeer device->ldv_intr_handler = nxge_tx_intr; 9786495Sspeer } else { 9796495Sspeer device->is_rxdma = B_TRUE; 9806495Sspeer device->is_txdma = B_FALSE; 9816495Sspeer device->ldv_intr_handler = nxge_rx_intr; 9826495Sspeer } 9836495Sspeer device->is_mif = B_FALSE; 9846495Sspeer device->is_mac = B_FALSE; 9856495Sspeer device->is_syserr = B_FALSE; 9866495Sspeer device->use_timer = B_FALSE; /* Set to B_TRUE for syserr only. */ 9876495Sspeer 9886495Sspeer device->channel = dc->channel; 9896495Sspeer device->vdma_index = dc->page; 9906495Sspeer device->func = nxge->function_num; 9916495Sspeer device->ldgp = group; 9926495Sspeer device->ldv_flags = 0; 9936495Sspeer device->ldv_ldf_masks = 0; 9946495Sspeer 9956495Sspeer device->nxgep = nxge; 9966495Sspeer 9976495Sspeer /* 9986495Sspeer * This code seems to imply a strict 1-to-1 correspondence. 9996495Sspeer */ 10006495Sspeer group->nldvs++; 10016495Sspeer group->ldvp = device; 10026495Sspeer 10036495Sspeer control->nldvs++; 10046495Sspeer control->ldg_intrs++; 10056495Sspeer 10066495Sspeer NXGE_DEBUG_MSG((nxge, HIO_CTL, "<== nxge_hio_ldsv_add")); 10076495Sspeer 10086495Sspeer return (0); 10096495Sspeer } 10106495Sspeer 10116495Sspeer /* 10126495Sspeer * nxge_hio_ldsv_im 10136495Sspeer * 10146495Sspeer * Manage a VLDG's interrupts. 10156495Sspeer * 10166495Sspeer * Arguments: 10176495Sspeer * nxge 10186495Sspeer * group The VLDG to manage 10196495Sspeer * 10206495Sspeer * Notes: 10216495Sspeer * There are 8 sets of 4 64-bit registers per VR, 1 per LDG. 10226495Sspeer * That sums to 256 bytes of virtual PIO_LDSV space. 10236495Sspeer * 10246495Sspeer * VLDG0 starts at offset 0, 10256495Sspeer * VLDG1 starts at offset 32, etc. 10266495Sspeer * 10276495Sspeer * Each set consists of 4 registers: 10286495Sspeer * Logical Device State Vector 0. LDSV0 10296495Sspeer * Logical Device State Vector 1. LDSV1 10306495Sspeer * Logical Device State Vector 2. LDSV2 10316495Sspeer * Logical Device Group Interrupt Management. LDGIMGN 10326495Sspeer * 10336495Sspeer * The first three (LDSVx) are read-only. The 4th register is the 10346495Sspeer * LDGIMGN, the LDG Interrupt Management register, which is used to 10356495Sspeer * arm the LDG, or set its timer. 10366495Sspeer * 10376495Sspeer * The offset to write to is calculated as follows: 10386495Sspeer * 10396495Sspeer * 0x2000 + (VLDG << 4) + offset, where: 10406495Sspeer * VDLG is the virtual group, i.e., index of the LDG. 10416495Sspeer * offset is the offset (alignment 8) of the register 10426495Sspeer * to read or write. 10436495Sspeer * 10446495Sspeer * So, for example, if we wanted to arm the first TDC of VRx, we would 10456495Sspeer * calculate the address as: 10466495Sspeer * 10476495Sspeer * 0x2000 + (0 << 4) + 0x18 = 0x18 10486495Sspeer * 10496495Sspeer * Context: 10506495Sspeer * Guest domain 10516495Sspeer * 10526495Sspeer */ 10536495Sspeer void 10546495Sspeer nxge_hio_ldsv_im( 10556495Sspeer /* Read any register in the PIO_LDSV space. */ 10566495Sspeer nxge_t *nxge, 10576495Sspeer nxge_ldg_t *group, 10586495Sspeer pio_ld_op_t op, 10596495Sspeer uint64_t *value) 10606495Sspeer { 10616495Sspeer uint64_t offset = VLDG_OFFSET; 10626495Sspeer 10636495Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */ 10646495Sspeer offset += (op * sizeof (uint64_t)); /* 0, 8, 16, 24 */ 10656495Sspeer 10666495Sspeer NXGE_REG_RD64(nxge->npi_handle, offset, value); 10676495Sspeer } 10686495Sspeer 10696495Sspeer void 10706495Sspeer nxge_hio_ldgimgn( 10716495Sspeer /* Write the PIO_LDGIMGN register. */ 10726495Sspeer nxge_t *nxge, 10736495Sspeer nxge_ldg_t *group) 10746495Sspeer { 10756495Sspeer uint64_t offset = VLDG_OFFSET; 10766495Sspeer ldgimgm_t mgm; 10776495Sspeer 10786495Sspeer offset += group->vldg_index << VLDG_SLL; /* bits 7:5 */ 10796495Sspeer offset += (PIO_LDGIMGN * sizeof (uint64_t)); /* 24 */ 10806495Sspeer 10816495Sspeer mgm.value = 0; 10826495Sspeer if (group->arm) { 10836495Sspeer mgm.bits.ldw.arm = 1; 10846495Sspeer mgm.bits.ldw.timer = group->ldg_timer; 10856495Sspeer } else { 10866495Sspeer mgm.bits.ldw.arm = 0; 10876495Sspeer mgm.bits.ldw.timer = 0; 10886495Sspeer } 10896495Sspeer NXGE_REG_WR64(nxge->npi_handle, offset, mgm.value); 10906495Sspeer } 1091