/* * We find out if we support MSI during this, and the register layout * depends on the MSI (doh). Don't acces the device specific bits in * BAR 0 before calling it! */ int virtio_register_ints(struct virtio_softc *sc, struct virtio_int_handler *config_handler, struct virtio_int_handler vq_handlers[]) { int ret; int intr_types; /* Default offset until MSI-X is enabled, if ever. */ sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSIX; /* Determine which types of interrupts are supported */ ret = ddi_intr_get_supported_types(sc->sc_dev, &intr_types); if (ret != DDI_SUCCESS) { dev_err(sc->sc_dev, CE_WARN, "Can't get supported int types"); goto out_inttype; } /* If we have msi, let's use them. */ if (intr_types & (DDI_INTR_TYPE_MSIX | DDI_INTR_TYPE_MSI)) { ret = virtio_register_msi(sc, config_handler, vq_handlers, intr_types); if (!ret) return (0); } /* Fall back to old-fashioned interrupts. */ if (intr_types & DDI_INTR_TYPE_FIXED) { dev_debug(sc->sc_dev, CE_WARN, "Using legacy interrupts"); return (virtio_register_intx(sc, config_handler, vq_handlers)); } dev_err(sc->sc_dev, CE_WARN, "MSI failed and fixed interrupts not supported. Giving up."); ret = DDI_FAILURE; out_inttype: return (ret); }
static int virtionet_intr_setup(virtionet_state_t *sp) { int rc; int itypes; rc = ddi_intr_get_supported_types(sp->dip, &itypes); if (rc != DDI_SUCCESS) { return (DDI_FAILURE); } if (itypes & DDI_INTR_TYPE_MSIX) { cmn_err(CE_NOTE, "Detected MSIX interrupt support"); } if (itypes & DDI_INTR_TYPE_MSI) { cmn_err(CE_NOTE, "Detected MSI interrupt support"); } if (itypes & DDI_INTR_TYPE_FIXED) { cmn_err(CE_NOTE, "Detected FIXED interrupt support"); } rc = virtio_fixed_intr_setup(sp, virtionet_intr); return (DDI_SUCCESS); }
/* * Autoconfiguration entry points. */ int efe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) { ddi_acc_handle_t pci; int types; int count; int actual; uint_t pri; efe_t *efep; mac_register_t *macp; switch (cmd) { case DDI_ATTACH: break; case DDI_RESUME: efep = ddi_get_driver_private(dip); return (efe_resume(efep)); default: return (DDI_FAILURE); } /* * PCI configuration. */ if (pci_config_setup(dip, &pci) != DDI_SUCCESS) { efe_error(dip, "unable to setup PCI configuration!"); return (DDI_FAILURE); } pci_config_put16(pci, PCI_CONF_COMM, pci_config_get16(pci, PCI_CONF_COMM) | PCI_COMM_MAE | PCI_COMM_ME); pci_config_teardown(&pci); if (ddi_intr_get_supported_types(dip, &types) != DDI_SUCCESS || !(types & DDI_INTR_TYPE_FIXED)) { efe_error(dip, "fixed interrupts not supported!"); return (DDI_FAILURE); } if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &count) != DDI_SUCCESS || count != 1) { efe_error(dip, "no fixed interrupts available!"); return (DDI_FAILURE); } /* * Initialize soft state. */ efep = kmem_zalloc(sizeof (efe_t), KM_SLEEP); ddi_set_driver_private(dip, efep); efep->efe_dip = dip; if (ddi_regs_map_setup(dip, 1, (caddr_t *)&efep->efe_regs, 0, 0, &efe_regs_acc_attr, &efep->efe_regs_acch) != DDI_SUCCESS) { efe_error(dip, "unable to setup register mapping!"); goto failure; } efep->efe_rx_ring = efe_ring_alloc(efep->efe_dip, RXDESCL); if (efep->efe_rx_ring == NULL) { efe_error(efep->efe_dip, "unable to allocate rx ring!"); goto failure; } efep->efe_tx_ring = efe_ring_alloc(efep->efe_dip, TXDESCL); if (efep->efe_tx_ring == NULL) { efe_error(efep->efe_dip, "unable to allocate tx ring!"); goto failure; } if (ddi_intr_alloc(dip, &efep->efe_intrh, DDI_INTR_TYPE_FIXED, 0, count, &actual, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS || actual != count) { efe_error(dip, "unable to allocate fixed interrupt!"); goto failure; } if (ddi_intr_get_pri(efep->efe_intrh, &pri) != DDI_SUCCESS || pri >= ddi_intr_get_hilevel_pri()) { efe_error(dip, "unable to get valid interrupt priority!"); goto failure; } mutex_init(&efep->efe_intrlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); mutex_init(&efep->efe_txlock, NULL, MUTEX_DRIVER, DDI_INTR_PRI(pri)); /* * Initialize device. */ mutex_enter(&efep->efe_intrlock); mutex_enter(&efep->efe_txlock); efe_reset(efep); mutex_exit(&efep->efe_txlock); mutex_exit(&efep->efe_intrlock); /* Use factory address as default */ efe_getaddr(efep, efep->efe_macaddr); /* * Enable the ISR. */ if (ddi_intr_add_handler(efep->efe_intrh, efe_intr, efep, NULL) != DDI_SUCCESS) { efe_error(dip, "unable to add interrupt handler!"); goto failure; } if (ddi_intr_enable(efep->efe_intrh) != DDI_SUCCESS) { efe_error(dip, "unable to enable interrupt!"); goto failure; } /* * Allocate MII resources. */ if ((efep->efe_miih = mii_alloc(efep, dip, &efe_mii_ops)) == NULL) { efe_error(dip, "unable to allocate mii resources!"); goto failure; } /* * Allocate MAC resources. */ if ((macp = mac_alloc(MAC_VERSION)) == NULL) { efe_error(dip, "unable to allocate mac resources!"); goto failure; } macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; macp->m_driver = efep; macp->m_dip = dip; macp->m_src_addr = efep->efe_macaddr; macp->m_callbacks = &efe_m_callbacks; macp->m_min_sdu = 0; macp->m_max_sdu = ETHERMTU; macp->m_margin = VLAN_TAGSZ; if (mac_register(macp, &efep->efe_mh) != 0) { efe_error(dip, "unable to register with mac!"); goto failure; } mac_free(macp); ddi_report_dev(dip); return (DDI_SUCCESS); failure: if (macp != NULL) { mac_free(macp); } if (efep->efe_miih != NULL) { mii_free(efep->efe_miih); } if (efep->efe_intrh != NULL) { (void) ddi_intr_disable(efep->efe_intrh); (void) ddi_intr_remove_handler(efep->efe_intrh); (void) ddi_intr_free(efep->efe_intrh); } mutex_destroy(&efep->efe_txlock); mutex_destroy(&efep->efe_intrlock); if (efep->efe_tx_ring != NULL) { efe_ring_free(&efep->efe_tx_ring); } if (efep->efe_rx_ring != NULL) { efe_ring_free(&efep->efe_rx_ring); } if (efep->efe_regs_acch != NULL) { ddi_regs_map_free(&efep->efe_regs_acch); } kmem_free(efep, sizeof (efe_t)); return (DDI_FAILURE); }
/** * Sets IRQ for VMMDev. * * @returns Solaris error code. * @param pDip Pointer to the device info structure. */ static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip) { LogFlow((DEVICE_NAME "::AddIRQ: pDip=%p\n", pDip)); int IntrType = 0; int rc = ddi_intr_get_supported_types(pDip, &IntrType); if (rc == DDI_SUCCESS) { /* We won't need to bother about MSIs. */ if (IntrType & DDI_INTR_TYPE_FIXED) { int IntrCount = 0; rc = ddi_intr_get_nintrs(pDip, IntrType, &IntrCount); if ( rc == DDI_SUCCESS && IntrCount > 0) { int IntrAvail = 0; rc = ddi_intr_get_navail(pDip, IntrType, &IntrAvail); if ( rc == DDI_SUCCESS && IntrAvail > 0) { /* Allocated kernel memory for the interrupt handles. The allocation size is stored internally. */ g_pIntr = RTMemAlloc(IntrCount * sizeof(ddi_intr_handle_t)); if (g_pIntr) { int IntrAllocated; rc = ddi_intr_alloc(pDip, g_pIntr, IntrType, 0, IntrCount, &IntrAllocated, DDI_INTR_ALLOC_NORMAL); if ( rc == DDI_SUCCESS && IntrAllocated > 0) { g_cIntrAllocated = IntrAllocated; uint_t uIntrPriority; rc = ddi_intr_get_pri(g_pIntr[0], &uIntrPriority); if (rc == DDI_SUCCESS) { /* Initialize the mutex. */ mutex_init(&g_IrqMtx, NULL, MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority)); /* Assign interrupt handler functions and enable interrupts. */ for (int i = 0; i < IntrAllocated; i++) { rc = ddi_intr_add_handler(g_pIntr[i], (ddi_intr_handler_t *)VBoxGuestSolarisISR, NULL /* No Private Data */, NULL); if (rc == DDI_SUCCESS) rc = ddi_intr_enable(g_pIntr[i]); if (rc != DDI_SUCCESS) { /* Changing local IntrAllocated to hold so-far allocated handles for freeing. */ IntrAllocated = i; break; } } if (rc == DDI_SUCCESS) return rc; /* Remove any assigned handlers */ LogRel((DEVICE_NAME ":failed to assign IRQs allocated=%d\n", IntrAllocated)); for (int x = 0; x < IntrAllocated; x++) ddi_intr_remove_handler(g_pIntr[x]); } else LogRel((DEVICE_NAME "::AddIRQ: failed to get priority of interrupt. rc=%d\n", rc)); /* Remove allocated IRQs, too bad we can free only one handle at a time. */ for (int k = 0; k < g_cIntrAllocated; k++) ddi_intr_free(g_pIntr[k]); } else LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", IntrCount)); RTMemFree(g_pIntr); } else LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", IntrCount)); } else LogRel((DEVICE_NAME "::AddIRQ: failed to get or insufficient available IRQs. rc=%d IntrAvail=%d\n", rc, IntrAvail)); } else LogRel((DEVICE_NAME "::AddIRQ: failed to get or insufficient number of IRQs. rc=%d IntrCount=%d\n", rc, IntrCount)); } else LogRel((DEVICE_NAME "::AddIRQ: invalid irq type. IntrType=%#x\n", IntrType)); } else LogRel((DEVICE_NAME "::AddIRQ: failed to get supported interrupt types\n")); return rc; }
/** * Sets IRQ for VMMDev. * * @returns Solaris error code. * @param pDip Pointer to the device info structure. */ static int vgdrvSolarisAddIRQ(dev_info_t *pDip) { LogFlow(("vgdrvSolarisAddIRQ: pDip=%p\n", pDip)); /* Get the types of interrupt supported for this hardware. */ int fIntrType = 0; int rc = ddi_intr_get_supported_types(pDip, &fIntrType); if (rc == DDI_SUCCESS) { /* We only support fixed interrupts at this point, not MSIs. */ if (fIntrType & DDI_INTR_TYPE_FIXED) { /* Verify the number of interrupts supported by this device. There can only be one fixed interrupt. */ int cIntrCount = 0; rc = ddi_intr_get_nintrs(pDip, fIntrType, &cIntrCount); if ( rc == DDI_SUCCESS && cIntrCount == 1) { /* Allocated kernel memory for the interrupt handle. The allocation size is stored internally. */ g_pahIntrs = RTMemAllocZ(cIntrCount * sizeof(ddi_intr_handle_t)); if (g_pahIntrs) { /* Allocate the interrupt for this device and verify the allocation. */ int cIntrAllocated; rc = ddi_intr_alloc(pDip, g_pahIntrs, fIntrType, 0 /* interrupt number */, cIntrCount, &cIntrAllocated, DDI_INTR_ALLOC_NORMAL); if ( rc == DDI_SUCCESS && cIntrAllocated == 1) { /* Get the interrupt priority assigned by the system. */ uint_t uIntrPriority; rc = ddi_intr_get_pri(g_pahIntrs[0], &uIntrPriority); if (rc == DDI_SUCCESS) { /* Check if the interrupt priority is scheduler level or above, if so we need to use a high-level and low-level interrupt handlers with corresponding mutexes. */ cmn_err(CE_CONT, "!vboxguest: uIntrPriority=%d hilevel_pri=%d\n", uIntrPriority, ddi_intr_get_hilevel_pri()); if (uIntrPriority >= ddi_intr_get_hilevel_pri()) { /* Initialize the high-level mutex. */ mutex_init(&g_HighLevelIrqMtx, NULL /* pszDesc */, MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority)); /* Assign interrupt handler function to the interrupt handle. */ rc = ddi_intr_add_handler(g_pahIntrs[0], (ddi_intr_handler_t *)&vgdrvSolarisHighLevelISR, NULL /* pvArg1 */, NULL /* pvArg2 */); if (rc == DDI_SUCCESS) { /* Add the low-level interrupt handler. */ rc = ddi_intr_add_softint(pDip, &g_hSoftIntr, DDI_INTR_SOFTPRI_MAX, (ddi_intr_handler_t *)&vgdrvSolarisISR, NULL /* pvArg1 */); if (rc == DDI_SUCCESS) { /* Initialize the low-level mutex at the corresponding level. */ mutex_init(&g_IrqMtx, NULL /* pszDesc */, MUTEX_DRIVER, DDI_INTR_PRI(DDI_INTR_SOFTPRI_MAX)); g_fSoftIntRegistered = true; /* Enable the high-level interrupt. */ rc = ddi_intr_enable(g_pahIntrs[0]); if (rc == DDI_SUCCESS) return rc; LogRel((DEVICE_NAME "::AddIRQ: failed to enable interrupt. rc=%d\n", rc)); mutex_destroy(&g_IrqMtx); } else LogRel((DEVICE_NAME "::AddIRQ: failed to add soft interrupt handler. rc=%d\n", rc)); ddi_intr_remove_handler(g_pahIntrs[0]); } else LogRel((DEVICE_NAME "::AddIRQ: failed to add high-level interrupt handler. rc=%d\n", rc)); mutex_destroy(&g_HighLevelIrqMtx); } else { /* Interrupt handler runs at reschedulable level, initialize the mutex at the given priority. */ mutex_init(&g_IrqMtx, NULL /* pszDesc */, MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority)); /* Assign interrupt handler function to the interrupt handle. */ rc = ddi_intr_add_handler(g_pahIntrs[0], (ddi_intr_handler_t *)vgdrvSolarisISR, NULL /* pvArg1 */, NULL /* pvArg2 */); if (rc == DDI_SUCCESS) { /* Enable the interrupt. */ rc = ddi_intr_enable(g_pahIntrs[0]); if (rc == DDI_SUCCESS) return rc; LogRel((DEVICE_NAME "::AddIRQ: failed to enable interrupt. rc=%d\n", rc)); mutex_destroy(&g_IrqMtx); } } } else LogRel((DEVICE_NAME "::AddIRQ: failed to get priority of interrupt. rc=%d\n", rc)); Assert(cIntrAllocated == 1); ddi_intr_free(g_pahIntrs[0]); } else LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", cIntrCount)); RTMemFree(g_pahIntrs); } else LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", cIntrCount)); } else LogRel((DEVICE_NAME "::AddIRQ: failed to get or insufficient number of IRQs. rc=%d cIntrCount=%d\n", rc, cIntrCount)); } else LogRel((DEVICE_NAME "::AddIRQ: fixed-type interrupts not supported. IntrType=%#x\n", fIntrType)); } else LogRel((DEVICE_NAME "::AddIRQ: failed to get supported interrupt types. rc=%d\n", rc)); return rc; }