示例#1
0
文件: px.c 项目: apprisi/illumos-gate
/* ARGSUSED */
int
px_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    ddi_intr_handle_impl_t *hdlp, void *result)
{
	int	intr_types, ret = DDI_SUCCESS;
	px_t	*px_p = DIP_TO_STATE(dip);

	DBG(DBG_INTROPS, dip, "px_intr_ops: rdip=%s%d\n",
	    ddi_driver_name(rdip), ddi_get_instance(rdip));

	/* Process DDI_INTROP_SUPPORTED_TYPES request here */
	if (intr_op == DDI_INTROP_SUPPORTED_TYPES) {
		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
		    DDI_INTR_TYPE_FIXED : 0;

		if ((pci_msi_get_supported_type(rdip,
		    &intr_types)) == DDI_SUCCESS) {
			/*
			 * Double check supported interrupt types vs.
			 * what the host bridge supports.
			 */
			*(int *)result |= intr_types;
		}

		*(int *)result &=
		    (px_force_intx_support ?
		    (px_p->px_supp_intr_types | DDI_INTR_TYPE_FIXED) :
		    px_p->px_supp_intr_types);
		return (*(int *)result ? DDI_SUCCESS : DDI_FAILURE);
	}

	/*
	 * PCI-E nexus driver supports fixed, MSI and MSI-X interrupts.
	 * Return failure if interrupt type is not supported.
	 */
	switch (hdlp->ih_type) {
	case DDI_INTR_TYPE_FIXED:
		ret = px_intx_ops(dip, rdip, intr_op, hdlp, result);
		break;
	case DDI_INTR_TYPE_MSI:
	case DDI_INTR_TYPE_MSIX:
		ret = px_msix_ops(dip, rdip, intr_op, hdlp, result);
		break;
	default:
		ret = DDI_ENOTSUP;
		break;
	}

	return (ret);
}
示例#2
0
static int
acebus_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    ddi_intr_handle_impl_t *hdlp, void *result)
{
#ifdef DEBUG
	ebus_devstate_t *ebus_p = get_acebus_soft_state(ddi_get_instance(dip));
#endif
	int8_t		*name, *device_type;
	int32_t		i, max_children, max_device_types, len;

	/*
	 * NOTE: These ops below will never be supported in this nexus
	 * driver, hence they always return immediately.
	 */
	switch (intr_op) {
	case DDI_INTROP_GETCAP:
		*(int *)result = DDI_INTR_FLAG_LEVEL;
		return (DDI_SUCCESS);
	case DDI_INTROP_SUPPORTED_TYPES:
		*(int *)result = i_ddi_get_intx_nintrs(rdip) ?
		    DDI_INTR_TYPE_FIXED : 0;
		return (DDI_SUCCESS);
	case DDI_INTROP_SETCAP:
	case DDI_INTROP_SETMASK:
	case DDI_INTROP_CLRMASK:
	case DDI_INTROP_GETPENDING:
		return (DDI_ENOTSUP);
	default:
		break;
	}

	if (hdlp->ih_pri)
		goto done;

	/*
	 * This is a hack to set the PIL for the devices under ebus.
	 * We first look up a device by it's specific name, if we can't
	 * match the name, we try and match it's device_type property.
	 * Lastly we default a PIL level of 1.
	 */
	DBG1(D_INTR, ebus_p, "ebus_p %p\n", ebus_p);

	name = ddi_get_name(rdip);
	max_children = sizeof (acebus_name_to_pil) /
	    sizeof (struct ebus_string_to_pil);

	for (i = 0; i < max_children; i++) {
		if (strcmp(acebus_name_to_pil[i].string, name) == 0) {
			DBG2(D_INTR, ebus_p, "child name %s; match PIL %d\n",
			    acebus_name_to_pil[i].string,
			    acebus_name_to_pil[i].pil);

			hdlp->ih_pri = acebus_name_to_pil[i].pil;
			goto done;
		}
	}

	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
	    "device_type", (caddr_t)&device_type, &len) == DDI_SUCCESS) {

		max_device_types = sizeof (acebus_device_type_to_pil) /
		    sizeof (struct ebus_string_to_pil);

		for (i = 0; i < max_device_types; i++) {
			if (strcmp(acebus_device_type_to_pil[i].string,
			    device_type) == 0) {
				DBG2(D_INTR, ebus_p,
				    "Device type %s; match PIL %d\n",
				    acebus_device_type_to_pil[i].string,
				    acebus_device_type_to_pil[i].pil);

				hdlp->ih_pri = acebus_device_type_to_pil[i].pil;
				break;
			}
		}

		kmem_free(device_type, len);
	}

	/*
	 * If we get here, we need to set a default value
	 * for the PIL.
	 */
	if (hdlp->ih_pri == 0) {
		hdlp->ih_pri = 1;
		cmn_err(CE_WARN, "%s%d assigning default interrupt level %d "
		    "for device %s%d", ddi_driver_name(dip),
		    ddi_get_instance(dip), hdlp->ih_pri, ddi_driver_name(rdip),
		    ddi_get_instance(rdip));
	}

done:
	/* Pass up the request to our parent. */
	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
}
示例#3
0
static int
isa_intr_ops(dev_info_t *pdip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    ddi_intr_handle_impl_t *hdlp, void *result)
{
	struct intrspec *ispec;
#if defined(__xpv)
	int cons, ttyn;

	cons = console_hypervisor_dev_type(&ttyn);
#endif
	if (pseudo_isa)
		return (i_ddi_intr_ops(pdip, rdip, intr_op, hdlp, result));


	/* Process the interrupt operation */
	switch (intr_op) {
	case DDI_INTROP_GETCAP:
		/* First check with pcplusmp */
		if (psm_intr_ops == NULL)
			return (DDI_FAILURE);

		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_CAP, result)) {
			*(int *)result = 0;
			return (DDI_FAILURE);
		}
		break;
	case DDI_INTROP_SETCAP:
		if (psm_intr_ops == NULL)
			return (DDI_FAILURE);

		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_CAP, result))
			return (DDI_FAILURE);
		break;
	case DDI_INTROP_ALLOC:
		ASSERT(hdlp->ih_type == DDI_INTR_TYPE_FIXED);
		return (isa_alloc_intr_fixed(rdip, hdlp, result));
	case DDI_INTROP_FREE:
		ASSERT(hdlp->ih_type == DDI_INTR_TYPE_FIXED);
		return (isa_free_intr_fixed(rdip, hdlp));
	case DDI_INTROP_GETPRI:
		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
			return (DDI_FAILURE);
		*(int *)result = ispec->intrspec_pri;
		break;
	case DDI_INTROP_SETPRI:
		/* Validate the interrupt priority passed to us */
		if (*(int *)result > LOCK_LEVEL)
			return (DDI_FAILURE);

		/* Ensure that PSM is all initialized and ispec is ok */
		if ((psm_intr_ops == NULL) ||
		    ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL))
			return (DDI_FAILURE);

		/* update the ispec with the new priority */
		ispec->intrspec_pri =  *(int *)result;
		break;
	case DDI_INTROP_ADDISR:
		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
			return (DDI_FAILURE);
		ispec->intrspec_func = hdlp->ih_cb_func;
		break;
	case DDI_INTROP_REMISR:
		if (hdlp->ih_type != DDI_INTR_TYPE_FIXED)
			return (DDI_FAILURE);
		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
			return (DDI_FAILURE);
		ispec->intrspec_func = (uint_t (*)()) 0;
		break;
	case DDI_INTROP_ENABLE:
		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
			return (DDI_FAILURE);

		/* Call psmi to translate irq with the dip */
		if (psm_intr_ops == NULL)
			return (DDI_FAILURE);

#if defined(__xpv)
		/*
		 * if the hypervisor is using an isa serial port for the
		 * console, make sure we don't try to use that interrupt as
		 * it will cause us to panic when xen_bind_pirq() fails.
		 */
		if (cons == CONS_TTY && ispec->intrspec_vec == asy_intrs[ttyn])
			return (DDI_FAILURE);
#endif
		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_XLATE_VECTOR,
		    (int *)&hdlp->ih_vector) == PSM_FAILURE)
			return (DDI_FAILURE);

		/* Add the interrupt handler */
		if (!add_avintr((void *)hdlp, ispec->intrspec_pri,
		    hdlp->ih_cb_func, DEVI(rdip)->devi_name, hdlp->ih_vector,
		    hdlp->ih_cb_arg1, hdlp->ih_cb_arg2, NULL, rdip))
			return (DDI_FAILURE);
		break;
	case DDI_INTROP_DISABLE:
		if ((ispec = isa_get_ispec(rdip, hdlp->ih_inum)) == NULL)
			return (DDI_FAILURE);

		/* Call psm_ops() to translate irq with the dip */
		if (psm_intr_ops == NULL)
			return (DDI_FAILURE);

		((ihdl_plat_t *)hdlp->ih_private)->ip_ispecp = ispec;
		(void) (*psm_intr_ops)(rdip, hdlp,
		    PSM_INTR_OP_XLATE_VECTOR, (int *)&hdlp->ih_vector);

		/* Remove the interrupt handler */
		rem_avintr((void *)hdlp, ispec->intrspec_pri,
		    hdlp->ih_cb_func, hdlp->ih_vector);
		break;
	case DDI_INTROP_SETMASK:
		if (psm_intr_ops == NULL)
			return (DDI_FAILURE);

		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_SET_MASK, NULL))
			return (DDI_FAILURE);
		break;
	case DDI_INTROP_CLRMASK:
		if (psm_intr_ops == NULL)
			return (DDI_FAILURE);

		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_CLEAR_MASK, NULL))
			return (DDI_FAILURE);
		break;
	case DDI_INTROP_GETPENDING:
		if (psm_intr_ops == NULL)
			return (DDI_FAILURE);

		if ((*psm_intr_ops)(rdip, hdlp, PSM_INTR_OP_GET_PENDING,
		    result)) {
			*(int *)result = 0;
			return (DDI_FAILURE);
		}
		break;
	case DDI_INTROP_NAVAIL:
	case DDI_INTROP_NINTRS:
		*(int *)result = i_ddi_get_intx_nintrs(rdip);
		if (*(int *)result == 0) {
			return (DDI_FAILURE);
		}
		break;
	case DDI_INTROP_SUPPORTED_TYPES:
		*(int *)result = DDI_INTR_TYPE_FIXED;	/* Always ... */
		break;
	default:
		return (DDI_FAILURE);
	}

	return (DDI_SUCCESS);
}