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