int ddi_add_softintr(dev_info_t *dip, int preference, ddi_softintr_t *idp, ddi_iblock_cookie_t *iblock_cookiep, ddi_idevice_cookie_t *idevice_cookiep, uint_t (*int_handler)(caddr_t int_handler_arg), caddr_t int_handler_arg) { ddi_softint_handle_t *hdl_p; uint64_t softpri; int ret; DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: name=%s%d dip=0x%p " "pref=0x%x\n", ddi_driver_name(dip), ddi_get_instance(dip), (void *)dip, preference)); if ((idp == NULL) || ((preference == DDI_SOFTINT_FIXED) && (iblock_cookiep == NULL))) return (DDI_FAILURE); /* Translate the priority preference */ if (preference == DDI_SOFTINT_FIXED) { softpri = (uint64_t)(uintptr_t)*iblock_cookiep; softpri = MIN(softpri, DDI_SOFT_INTR_PRI_H); } else { softpri = (uint64_t)((preference > DDI_SOFTINT_MED) ? DDI_SOFT_INTR_PRI_H : DDI_SOFT_INTR_PRI_M); } DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: preference 0x%x " "softpri 0x%lx\n", preference, (long)softpri)); hdl_p = kmem_zalloc(sizeof (ddi_softint_handle_t), KM_SLEEP); if ((ret = ddi_intr_add_softint(dip, hdl_p, softpri, (ddi_intr_handler_t *)int_handler, int_handler_arg)) != DDI_SUCCESS) { DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: " "ddi_intr_add_softint failed, ret 0x%x\n", ret)); kmem_free(hdl_p, sizeof (ddi_softint_handle_t)); return (DDI_FAILURE); } if (iblock_cookiep) *iblock_cookiep = (ddi_iblock_cookie_t)(uintptr_t)softpri; if (idevice_cookiep) { idevice_cookiep->idev_vector = 0; idevice_cookiep->idev_priority = softpri; } *idp = (ddi_softintr_t)hdl_p; DDI_INTR_APIDBG((CE_CONT, "ddi_add_softintr: dip = 0x%p, " "idp = 0x%p, ret = %x\n", (void *)dip, (void *)*idp, ret)); return (DDI_SUCCESS); }
static int eib_ctl_setup_cq(eib_t *ss, eib_vnic_t *vnic) { eib_chan_t *chan = vnic->vn_ctl_chan; ibt_cq_attr_t cq_attr; ibt_status_t ret; uint_t sz; int rv; /* * Allocate a completion queue for sending vhub table request * and vhub-update/vnic-alive messages and responses from the * gateway */ cq_attr.cq_sched = NULL; cq_attr.cq_flags = IBT_CQ_NO_FLAGS; if (ss->ei_hca_attrs->hca_max_cq_sz < EIB_CTL_CQ_SIZE) cq_attr.cq_size = ss->ei_hca_attrs->hca_max_cq_sz; else cq_attr.cq_size = EIB_CTL_CQ_SIZE; ret = ibt_alloc_cq(ss->ei_hca_hdl, &cq_attr, &chan->ch_cq_hdl, &sz); if (ret != IBT_SUCCESS) { EIB_DPRINTF_ERR(ss->ei_instance, "eib_ctl_setup_cq: " "ibt_alloc_cq(cq_sz=0x%lx) failed, ret=%d", cq_attr.cq_size, ret); goto ctl_setup_cq_fail; } /* * Set up other parameters for collecting completion information */ chan->ch_cq_sz = sz; chan->ch_wc = kmem_zalloc(sizeof (ibt_wc_t) * sz, KM_SLEEP); /* * Allocate soft interrupt for this vnic's control channel cq * handler and set up the IBTL cq handler. */ if ((rv = ddi_intr_add_softint(ss->ei_dip, &vnic->vn_ctl_si_hdl, EIB_SOFTPRI_CTL, eib_ctl_comp_handler, vnic)) != DDI_SUCCESS) { EIB_DPRINTF_ERR(ss->ei_instance, "eib_ctl_setup_cq: " "ddi_intr_add_softint() failed for vnic %d ctl qp, ret=%d", vnic->vn_instance, rv); goto ctl_setup_cq_fail; } /* * Now, set up this vnic's control channel completion queue handler */ ibt_set_cq_handler(chan->ch_cq_hdl, eib_ctl_comp_intr, vnic); ret = ibt_enable_cq_notify(chan->ch_cq_hdl, IBT_NEXT_COMPLETION); if (ret != IBT_SUCCESS) { EIB_DPRINTF_ERR(ss->ei_instance, "eib_ctl_setup_cq: " "ibt_enable_cq_notify() failed, ret=%d", ret); goto ctl_setup_cq_fail; } return (EIB_E_SUCCESS); ctl_setup_cq_fail: eib_rb_ctl_setup_cq(ss, vnic); return (EIB_E_FAILURE); }
/** * 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; }