Ejemplo n.º 1
0
int32_t
i_ddi_set_intr_weight(dev_info_t *dip, int32_t weight)
{
	int32_t oweight;

	oweight = i_ddi_get_intr_weight(dip);
	if ((weight > 0) && (oweight != weight))
		(void) ndi_prop_update_int(DDI_DEV_T_NONE, dip,
		    "ddi-intr-weight", weight);
	return (oweight);
}
Ejemplo n.º 2
0
/*
 * vdds_new_niu_node -- callback function to create a new NIU Hybrid node.
 */
static int
vdds_new_niu_node(dev_info_t *dip, void *arg, uint_t flags)
{
	vdds_cb_arg_t *cba = (vdds_cb_arg_t *)arg;
	char *compat[] = { "SUNW,niusl" };
	uint8_t macaddrbytes[ETHERADDRL];
	int interrupts[VDDS_MAX_VRINTRS];
	vdds_ranges_t	*prng;
	vdds_ranges_t	*prp;
	vdds_reg_t	reg;
	dev_info_t	*pdip;
	uint64_t	start;
	uint64_t	size;
	int		prnglen;
	int		nintr = 0;
	int		nrng;
	int		rnum;
	int		rv;

	DBG1(NULL, "Called dip=0x%p flags=0x%X", dip, flags);
	pdip = ddi_get_parent(dip);

	if (pdip == NULL) {
		DWARN(NULL, "Failed to get parent dip(dip=0x%p)", dip);
		return (DDI_WALK_ERROR);
	}

	/* create "network" property */
	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "network") !=
	    DDI_SUCCESS) {
		DERR(NULL, "Failed to create name property(dip=0x%p)", dip);
		return (DDI_WALK_ERROR);
	}

	/*
	 * create "niutype" property, it is set to n2niu to
	 * indicate NIU Hybrid node.
	 */
	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "niutype",
	    "n2niu") != DDI_SUCCESS) {
		DERR(NULL, "Failed to create niuopmode property(dip=0x%p)",
		    dip);
		return (DDI_WALK_ERROR);
	}

	/* create "compatible" property */
	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
	    compat, 1) != DDI_SUCCESS) {
		DERR(NULL, "Failed to create compatible property(dip=0x%p)",
		    dip);
		return (DDI_WALK_ERROR);
	}

	/* create "device_type" property */
	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
	    "device_type", "network") != DDI_SUCCESS) {
		DERR(NULL, "Failed to create device_type property(dip=0x%p)",
		    dip);
		return (DDI_WALK_ERROR);
	}

	/* create "reg" property */
	if (vdds_hv_niu_vr_getinfo(HVCOOKIE(cba->cookie),
	    &start, &size) != H_EOK) {
		DERR(NULL, "Failed to get vrinfo for cookie(0x%lX)",
		    cba->cookie);
			return (DDI_WALK_ERROR);
	}
	reg.addr_hi = HVCOOKIE(cba->cookie);
	reg.addr_lo = 0;
	reg.size_hi = 0;
	reg.size_lo = size;

	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "reg",
	    (int *)&reg, sizeof (reg) / sizeof (int)) != DDI_SUCCESS) {
		DERR(NULL, "Failed to create reg property(dip=0x%p)", dip);
		return (DDI_WALK_ERROR);
	}

	/*
	 * Modify the parent's ranges property to map the "reg" property
	 * of the new child.
	 */
	if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
	    "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) {
		DERR(NULL,
		    "Failed to get parent's ranges property(pdip=0x%p) rv=%d",
		    pdip, rv);
		return (DDI_WALK_ERROR);
	}
	nrng = prnglen/(sizeof (vdds_ranges_t));
	/*
	 * First scan all ranges to see if a range corresponding
	 * to this virtual NIU exists already.
	 */
	for (rnum = 0; rnum < nrng; rnum++) {
		prp = &prng[rnum];
		if (prp->child_hi == HVCOOKIE(cba->cookie)) {
			break;
		}
	}
	if (rnum == nrng) {
		/* Now to try to find an empty range */
		for (rnum = 0; rnum < nrng; rnum++) {
			prp = &prng[rnum];
			if (prp->child_hi == 0) {
				break;
			}
		}
	}
	if (rnum == nrng) {
		DERR(NULL, "No free ranges entry found");
		return (DDI_WALK_ERROR);
	}

	/*
	 * child_hi will have HV cookie as HV cookie is more like
	 * a port in the HybridIO.
	 */
	prp->child_hi = HVCOOKIE(cba->cookie);
	prp->child_lo = 0;
	prp->parent_hi = 0x80000000 | (start >> 32);
	prp->parent_lo = start & 0x00000000FFFFFFFF;
	prp->size_hi = (size >> 32);
	prp->size_lo = size & 0x00000000FFFFFFFF;

	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, pdip, "ranges",
	    (int *)prng, (nrng * 6)) != DDI_SUCCESS) {
		DERR(NULL, "Failed to update parent ranges prop(pdip=0x%p)",
		    pdip);
		return (DDI_WALK_ERROR);
	}
	kmem_free((void *)prng, prnglen);

	vnet_macaddr_ultostr(cba->macaddr, macaddrbytes);

	/*
	 * create "local-mac-address" property, this will be same as
	 * the vnet's mac-address.
	 */
	if (ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, "local-mac-address",
	    macaddrbytes, ETHERADDRL) != DDI_SUCCESS) {
		DERR(NULL, "Failed to update mac-addresses property(dip=0x%p)",
		    dip);
		return (DDI_WALK_ERROR);
	}

	rv = vdds_get_interrupts(cba->cookie, rnum, interrupts, &nintr);
	if (rv != 0) {
		DERR(NULL, "Failed to get interrupts for cookie=0x%lx",
		    cba->cookie);
		return (DDI_WALK_ERROR);
	}

	/* create "interrupts" property */
	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "interrupts",
	    interrupts, nintr) != DDI_SUCCESS) {
		DERR(NULL, "Failed to update interrupts property(dip=0x%p)",
		    dip);
		return (DDI_WALK_ERROR);
	}


	/* create "max_frame_size" property */
	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip, "max-frame-size",
	    cba->max_frame_size) != DDI_SUCCESS) {
		DERR(NULL, "Failed to update max-frame-size property(dip=0x%p)",
		    dip);
		return (DDI_WALK_ERROR);
	}

	cba->dip = dip;
	DBG1(NULL, "Returning dip=0x%p", dip);
	return (DDI_WALK_TERMINATE);
}
Ejemplo n.º 3
0
/*
 * vdds_new_nexus_node -- callback function to set all the properties
 *	a new NIU nexus node.
 */
static int
vdds_new_nexus_node(dev_info_t *dip, void *arg, uint_t flags)
{
	vdds_cb_arg_t	*cba = (vdds_cb_arg_t *)arg;
	char		*compat[] = { "SUNW,niumx" };
	vdds_ranges_t	*rangesp;
	vdds_reg_t	reg;
	uint64_t	nranges;
	int		n;

	DBG1(NULL, "Called dip=0x%p, flags=0x%X", dip, flags);

	/* create "niu" property */
	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip, "name", "niu") !=
	    DDI_SUCCESS) {
		DERR(NULL, "Failed to create name property(dip=0x%p)", dip);
		return (DDI_WALK_ERROR);
	}

	/* create "compatible" property */
	if (ndi_prop_update_string_array(DDI_DEV_T_NONE, dip, "compatible",
	    compat, 1) != DDI_SUCCESS) {
		DERR(NULL, "Failed to create compatible property(dip=0x%p)",
		    dip);
		return (DDI_WALK_ERROR);
	}

	/* create "device_type" property */
	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
	    "device_type", "sun4v") != DDI_SUCCESS) {
		DERR(NULL, "Failed to create device_type property(dip=0x%p)",
		    dip);
		return (DDI_WALK_ERROR);
	}

	/*
	 * create "reg" property. The first 28 bits of
	 * 'addr_hi'  are NIU cfg_handle, the 0xc in 28-31 bits
	 * indicates non-cacheable config.
	 */
	reg.addr_hi = 0xc0000000 | NIUCFGHDL(cba->cookie);
	reg.addr_lo = 0;
	reg.size_hi = 0;
	reg.size_lo = 0;
	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip,
	    "reg", (int *)&reg, sizeof (reg)/sizeof (int)) != DDI_SUCCESS) {
		DERR(NULL, "Failed to create reg property(dip=0x%p)", dip);
		return (DDI_WALK_ERROR);
	}

	/*
	 * Create VDDS_MAX_RANGES so that they are already in place
	 * before the children are created. While creating the child
	 * we just modify one of this ranges entries.
	 */
	nranges = VDDS_MAX_RANGES;  /* One range for each VR */
	rangesp = (vdds_ranges_t *)kmem_zalloc(
	    (sizeof (vdds_ranges_t) * nranges), KM_SLEEP);

	for (n = 0; n < nranges; n++) {
		/* zero all child_hi/lo */
		rangesp[n].child_hi = 0;
		rangesp[n].child_lo = 0;
	}

	if (ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges",
	    (int *)rangesp, (nranges * 6)) != DDI_SUCCESS) {
		DERR(NULL, "Failed to create ranges property(dip=0x%p)", dip);
		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
		return (DDI_WALK_ERROR);
	}

	/* create "#size-cells" property */
	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
	    "#size-cells", 2) != DDI_SUCCESS) {
		DERR(NULL, "Failed to create #size-cells property(dip=0x%p)",
		    dip);
		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
		return (DDI_WALK_ERROR);
	}

	/* create "#address-cells" property */
	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
	    "#address-cells", 2) != DDI_SUCCESS) {
		DERR(NULL, "Failed to create #address-cells prop(dip=0x%p)",
		    dip);
		kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
		return (DDI_WALK_ERROR);
	}

	kmem_free(rangesp, (sizeof (vdds_ranges_t) * nranges));
	cba->dip = dip;
	DBG1(NULL, "Returning (dip=0x%p)", dip);
	return (DDI_WALK_TERMINATE);
}
Ejemplo n.º 4
0
static ACPI_STATUS
acpidev_cpu_init(acpidev_walk_info_t *infop)
{
	int count;
	uint32_t pxmid;
	dev_info_t *dip;
	ACPI_HANDLE hdl;
	char unitaddr[64];
	char **compatpp;
	static char *compatible[] = {
		ACPIDEV_HID_PROCESSOR,
		ACPIDEV_TYPE_CPU,
		"cpu"
	};

	ASSERT(infop != NULL);
	dip = infop->awi_dip;
	hdl = infop->awi_hdl;

	/* Create "apic_id", "processor_id" and "proximity_id" properties. */
	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
	    ACPIDEV_PROP_NAME_PROCESSOR_ID, infop->awi_scratchpad[0]) !=
	    NDI_SUCCESS) {
		cmn_err(CE_WARN,
		    "!acpidev: failed to set processor_id property for %s.",
		    infop->awi_name);
		return (AE_ERROR);
	}
	if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
	    ACPIDEV_PROP_NAME_LOCALAPIC_ID, infop->awi_scratchpad[1]) !=
	    NDI_SUCCESS) {
		cmn_err(CE_WARN,
		    "!acpidev: failed to set apic_id property for %s.",
		    infop->awi_name);
		return (AE_ERROR);
	}
	if (ACPI_SUCCESS(acpidev_cpu_get_proximity_id(infop->awi_hdl,
	    infop->awi_scratchpad[1], &pxmid))) {
		if (ndi_prop_update_int(DDI_DEV_T_NONE, dip,
		    ACPIDEV_PROP_NAME_PROXIMITY_ID, pxmid) != NDI_SUCCESS) {
			cmn_err(CE_WARN, "!acpidev: failed to set proximity id "
			    "property for %s.", infop->awi_name);
			return (AE_ERROR);
		}
	}

	/* Set "compatible" property for CPU dip */
	count = sizeof (compatible) / sizeof (compatible[0]);
	if (infop->awi_info->Type == ACPI_TYPE_PROCESSOR) {
		compatpp = compatible;
	} else if (infop->awi_info->Type == ACPI_TYPE_DEVICE) {
		/*
		 * skip first item for pseudo processor HID.
		 * acpidev_set_compatible() will handle HID/CID for CPU device.
		 */
		compatpp = &compatible[1];
		count--;
	} else {
		return (AE_BAD_PARAMETER);
	}
	if (ACPI_FAILURE(acpidev_set_compatible(infop, compatpp, count))) {
		return (AE_ERROR);
	}

	/*
	 * Set device unit-address property.
	 * First try to generate meaningful unit address from _UID,
	 * then use Processor Id if that fails.
	 */
	if ((infop->awi_info->Valid & ACPI_VALID_UID) == 0 ||
	    acpidev_generate_unitaddr(infop->awi_info->UniqueId.String,
	    ACPIDEV_ARRAY_PARAM(acpidev_cpu_uid_formats),
	    unitaddr, sizeof (unitaddr)) == NULL) {
		(void) snprintf(unitaddr, sizeof (unitaddr), "%u",
		    (uint32_t)infop->awi_scratchpad[0]);
	}
	if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) {
		return (AE_ERROR);
	}

	/*
	 * Build binding information for CPUs.
	 */
	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
		if (ACPI_FAILURE(acpica_add_processor_to_map(
		    infop->awi_scratchpad[0], hdl, infop->awi_scratchpad[1]))) {
			cmn_err(CE_WARN, "!acpidev: failed to bind processor "
			    "id/object handle for %s.", infop->awi_name);
			return (AE_ERROR);
		}
	} else {
		ACPIDEV_DEBUG(CE_WARN,
		    "!acpidev: unknown operation type %u in acpidev_cpu_init.",
		    infop->awi_op_type);
		return (AE_BAD_PARAMETER);
	}

	return (AE_OK);
}
Ejemplo n.º 5
0
static int
ppb_initchild(dev_info_t *child)
{
	char name[MAXNAMELEN];
	ddi_acc_handle_t config_handle;
	ushort_t command_preserve, command;
	uint_t n;
	ushort_t bcr;
	uchar_t header_type;
	uchar_t min_gnt, latency_timer;
	ppb_devstate_t *ppb;

	/*
	 * Name the child
	 */
	if (ppb_name_child(child, name, MAXNAMELEN) != DDI_SUCCESS)
		return (DDI_FAILURE);

	ddi_set_name_addr(child, name);
	ddi_set_parent_data(child, NULL);

	/*
	 * Pseudo nodes indicate a prototype node with per-instance
	 * properties to be merged into the real h/w device node.
	 * The interpretation of the unit-address is DD[,F]
	 * where DD is the device id and F is the function.
	 */
	if (ndi_dev_is_persistent_node(child) == 0) {
		extern int pci_allow_pseudo_children;

		/*
		 * Try to merge the properties from this prototype
		 * node into real h/w nodes.
		 */
		if (ndi_merge_node(child, ppb_name_child) == DDI_SUCCESS) {
			/*
			 * Merged ok - return failure to remove the node.
			 */
			ppb_removechild(child);
			return (DDI_FAILURE);
		}

		/* workaround for ddivs to run under PCI */
		if (pci_allow_pseudo_children)
			return (DDI_SUCCESS);

		/*
		 * The child was not merged into a h/w node,
		 * but there's not much we can do with it other
		 * than return failure to cause the node to be removed.
		 */
		cmn_err(CE_WARN, "!%s@%s: %s.conf properties not merged",
		    ddi_driver_name(child), ddi_get_name_addr(child),
		    ddi_driver_name(child));
		ppb_removechild(child);
		return (DDI_NOT_WELL_FORMED);
	}

	ppb = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
	    ddi_get_instance(ddi_get_parent(child)));

	ddi_set_parent_data(child, NULL);

	/*
	 * If hardware is PM capable, set up the power info structure.
	 * This also ensures the the bus will not be off (0MHz) otherwise
	 * system panics during a bus access.
	 */
	if (PM_CAPABLE(ppb->ppb_pwr_p)) {
		/*
		 * Create a pwr_info struct for child.  Bus will be
		 * at full speed after creating info.
		 */
		pci_pwr_create_info(ppb->ppb_pwr_p, child);
#ifdef DEBUG
		ASSERT(ppb->ppb_pwr_p->current_lvl == PM_LEVEL_B0);
#endif
	}

	/*
	 * If configuration registers were previously saved by
	 * child (before it entered D3), then let the child do the
	 * restore to set up the config regs as it'll first need to
	 * power the device out of D3.
	 */
	if (ddi_prop_exists(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    "config-regs-saved-by-child") == 1) {
		DEBUG2(DBG_PWR, ddi_get_parent(child),
		    "INITCHILD: config regs to be restored by child"
		    " for %s@%s\n", ddi_node_name(child),
		    ddi_get_name_addr(child));

		return (DDI_SUCCESS);
	}

	DEBUG2(DBG_PWR, ddi_get_parent(child),
	    "INITCHILD: config regs setup for %s@%s\n",
	    ddi_node_name(child), ddi_get_name_addr(child));

	if (pci_config_setup(child, &config_handle) != DDI_SUCCESS) {
		if (PM_CAPABLE(ppb->ppb_pwr_p)) {
			pci_pwr_rm_info(ppb->ppb_pwr_p, child);
		}

		return (DDI_FAILURE);
	}

	/*
	 * Determine the configuration header type.
	 */
	header_type = pci_config_get8(config_handle, PCI_CONF_HEADER);

	/*
	 * Support for the "command-preserve" property.
	 */
	command_preserve = ddi_prop_get_int(DDI_DEV_T_ANY, child,
	    DDI_PROP_DONTPASS, "command-preserve", 0);
	command = pci_config_get16(config_handle, PCI_CONF_COMM);
	command &= (command_preserve | PCI_COMM_BACK2BACK_ENAB);
	command |= (ppb_command_default & ~command_preserve);
	pci_config_put16(config_handle, PCI_CONF_COMM, command);

	/*
	 * If the device has a bus control register then program it
	 * based on the settings in the command register.
	 */
	if ((header_type  & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
		bcr = pci_config_get8(config_handle, PCI_BCNF_BCNTRL);
		if (ppb_command_default & PCI_COMM_PARITY_DETECT)
			bcr |= PCI_BCNF_BCNTRL_PARITY_ENABLE;
		if (ppb_command_default & PCI_COMM_SERR_ENABLE)
			bcr |= PCI_BCNF_BCNTRL_SERR_ENABLE;
		bcr |= PCI_BCNF_BCNTRL_MAST_AB_MODE;
		pci_config_put8(config_handle, PCI_BCNF_BCNTRL, bcr);
	}

	/*
	 * Initialize cache-line-size configuration register if needed.
	 */
	if (ppb_set_cache_line_size_register &&
	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    "cache-line-size", 0) == 0) {
		pci_config_put8(config_handle, PCI_CONF_CACHE_LINESZ,
		    ppb->ppb_cache_line_size);
		n = pci_config_get8(config_handle, PCI_CONF_CACHE_LINESZ);
		if (n != 0) {
			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
			    "cache-line-size", n);
		}
	}

	/*
	 * Initialize latency timer configuration registers if needed.
	 */
	if (ppb_set_latency_timer_register &&
	    ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
	    "latency-timer", 0) == 0) {

		if ((header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
			latency_timer = ppb->ppb_latency_timer;
			pci_config_put8(config_handle, PCI_BCNF_LATENCY_TIMER,
			    ppb->ppb_latency_timer);
		} else {
			min_gnt = pci_config_get8(config_handle,
			    PCI_CONF_MIN_G);
			latency_timer = min_gnt * 8;
		}
		pci_config_put8(config_handle, PCI_CONF_LATENCY_TIMER,
		    latency_timer);
		n = pci_config_get8(config_handle, PCI_CONF_LATENCY_TIMER);
		if (n != 0) {
			(void) ndi_prop_update_int(DDI_DEV_T_NONE, child,
			    "latency-timer", n);
		}
	}

	/*
	 * SPARC PCIe FMA specific
	 *
	 * Note: parent_data for parent is created only if this is sparc PCI-E
	 * platform, for which, SG take a different route to handle device
	 * errors.
	 */
	if (ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) {
		if (pcie_init_cfghdl(child) != DDI_SUCCESS) {
			pci_config_teardown(&config_handle);
			return (DDI_FAILURE);
		}
		pcie_init_dom(child);
	}

	/*
	 * Check to see if the XMITS/PCI-X workaround applies.
	 */
	n = ddi_getprop(DDI_DEV_T_ANY, child, DDI_PROP_NOTPROM,
	    "pcix-update-cmd-reg", -1);

	if (n != -1) {
		extern void pcix_set_cmd_reg(dev_info_t *child, uint16_t value);
		DEBUG1(DBG_INIT_CLD, child, "Turning on XMITS NCPQ "
		    "Workaround: value = %x\n", n);
		pcix_set_cmd_reg(child, n);
	}
	pci_config_teardown(&config_handle);
	return (DDI_SUCCESS);
}
Ejemplo n.º 6
0
/*
 * nx1394_bus_ctl()
 *    This routine implements nexus bus ctl operations. Of importance are
 *    DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
 *    and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
 *    reg property on the child node and builds and sets the name
 *    (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where
 *    GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit
 *    address).
 */
static int
nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
    void *result)
{
	int status;

	TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, "");

	switch (op) {
	case DDI_CTLOPS_REPORTDEV: {
		dev_info_t *pdip = ddi_get_parent(rdip);
		cmn_err(CE_CONT, "?%s%d at %s%d",
		    ddi_node_name(rdip), ddi_get_instance(rdip),
		    ddi_node_name(pdip), ddi_get_instance(pdip));
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_INITCHILD: {
		dev_info_t *ocdip, *cdip = (dev_info_t *)arg;
		dev_info_t *pdip = ddi_get_parent(cdip);
		int reglen, i;
		uint32_t *regptr;
		char addr[MAXNAMELEN];

		TNF_PROBE_1(nx1394_bus_ctl_init_child,
		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, dip, cdip);

		i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
		    DDI_PROP_DONTPASS, "reg", (int **)&regptr,
		    (uint_t *)&reglen);

		if (i != DDI_PROP_SUCCESS) {
			cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found",
			    ddi_node_name(cdip), ddi_get_instance(cdip));
			TNF_PROBE_2(nx1394_bus_ctl,
			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg,
			    "Reg property not found", tnf_int, reason, i);
			TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
			    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
			    "initchild");
			return (DDI_NOT_WELL_FORMED);
		}

		ASSERT(reglen != 0);

		/*
		 * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA]
		 */
		if (regptr[2] || regptr[3]) {
			(void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
			    regptr[1], regptr[2], regptr[3]);
		} else {
			(void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
		}
		ddi_prop_free(regptr);
		ddi_set_name_addr(cdip, addr);

		/*
		 * Check for a node with the same name & addr as the current
		 * node. If such a node exists, return failure.
		 */
		if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) !=
		    NULL && ocdip != cdip) {
			cmn_err(CE_NOTE,
			    "!%s(%d): Duplicate dev_info node found %s@%s",
			    ddi_node_name(cdip), ddi_get_instance(cdip),
			    ddi_node_name(ocdip), addr);
			TNF_PROBE_1(nx1394_bus_ctl,
			    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg,
			    "Duplicate nodes");
			TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
			    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op,
			    "initchild");
			ddi_set_name_addr(cdip, NULL);
			return (DDI_NOT_WELL_FORMED);
		}

		/*
		 * If HAL (parent dip) has "active-dma-flush" property, then
		 * add property to child as well.  Workaround for active
		 * context flushing bug in Schizo rev 2.1 and 2.2.
		 */
		if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS,
		    "active-dma-flush") != 0) {
			status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
			    "active-dma-flush", 1);
			if (status != NDI_SUCCESS) {
				cmn_err(CE_NOTE, "!%s(%d): Unable to add "
				    "\"active-dma-flush\" property",
				    ddi_node_name(cdip),
				    ddi_get_instance(cdip));
				TNF_PROBE_1(nx1394_bus_ctl,
				    S1394_TNF_SL_NEXUS_ERROR, "", tnf_string,
				    msg, "Unable to add \"active-dma-flush\" "
				    "property");
				TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
				    S1394_TNF_SL_NEXUS_STACK, "", tnf_string,
				    op, "initchild");
				ddi_set_name_addr(cdip, NULL);
				return (DDI_NOT_WELL_FORMED);
			}
		}

		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit,
		    S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_UNINITCHILD: {
		ddi_prop_remove_all((dev_info_t *)arg);
		ddi_set_name_addr((dev_info_t *)arg, NULL);
		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "", tnf_string, op, "uninitchild");
		return (DDI_SUCCESS);
	}

	case DDI_CTLOPS_IOMIN: {
		status = ddi_ctlops(dip, rdip, op, arg, result);
		TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "", tnf_string, op, "iomin");
		return (status);
	}

	case DDI_CTLOPS_POWER: {
		return (DDI_SUCCESS);
	}

	/*
	 * These ops correspond to functions that "shouldn't" be called
	 * by a 1394 client driver.
	 */
	case DDI_CTLOPS_DMAPMAPC:
	case DDI_CTLOPS_REPORTINT:
	case DDI_CTLOPS_REGSIZE:
	case DDI_CTLOPS_NREGS:
	case DDI_CTLOPS_SIDDEV:
	case DDI_CTLOPS_SLAVEONLY:
	case DDI_CTLOPS_AFFINITY:
	case DDI_CTLOPS_POKE:
	case DDI_CTLOPS_PEEK: {
		cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)",
		    ddi_node_name(dip), ddi_get_instance(dip),
		    op, ddi_node_name(rdip), ddi_get_instance(rdip));
		TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "",
		    tnf_string, msg, "invalid op", tnf_int, op, op);
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (DDI_FAILURE);
	}

	/*
	 * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up
	 */
	default: {
		status = ddi_ctlops(dip, rdip, op, arg, result);
		TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK,
		    "");
		return (status);
	}
	}
}
Ejemplo n.º 7
0
boolean_t
check_if_device_is_pciex(dev_info_t *cdip, uchar_t bus, uchar_t dev,
    uchar_t func, boolean_t *slot_valid, ushort_t *slot_number,
    ushort_t *is_pci_bridge)
{
	boolean_t found_pciex = B_FALSE;
	ushort_t cap;
	ushort_t capsp;
	ushort_t cap_count = PCI_CAP_MAX_PTR;
	ushort_t status;
	uint32_t slot_cap;

	*slot_valid = B_FALSE;

	status = (*pci_getw_func)(bus, dev, func, PCI_CONF_STAT);
	if (!(status & PCI_STAT_CAP))
		return (B_FALSE);

	capsp = (*pci_getb_func)(bus, dev, func, PCI_CONF_CAP_PTR);
	while (cap_count-- && capsp >= PCI_CAP_PTR_OFF) {
		capsp &= PCI_CAP_PTR_MASK;
		cap = (*pci_getb_func)(bus, dev, func, capsp);

		if (cap == PCI_CAP_ID_PCI_E) {
#ifdef	DEBUG
			if (pci_boot_debug)
				cmn_err(CE_CONT, "PCI-Express (%x,%x,%x) "
				    "capability found\n", bus, dev, func);
#endif	/* DEBUG */

			status = (*pci_getw_func)(bus, dev, func, capsp + 2);
			/*
			 * See section 7.8.2 of PCI-Express Base Spec v1.0a
			 * for Device/Port Type.
			 * PCIE_PCIECAP_DEV_TYPE_PCIE2PCI implies that the
			 * device is a PCIe2PCI bridge
			 */
			*is_pci_bridge =
			    ((status & PCIE_PCIECAP_DEV_TYPE_MASK) ==
			    PCIE_PCIECAP_DEV_TYPE_PCIE2PCI) ? 1 : 0;

			/*
			 * Check for "Slot  Implemented" bit
			 * PCIE_PCIECAP_SLOT_IMPL implies that.
			 */
			if (status & PCIE_PCIECAP_SLOT_IMPL) {
				/* offset 14h is Slot Cap Register */
				slot_cap = (*pci_getl_func)(bus, dev, func,
				    capsp + PCIE_SLOTCAP);
				*slot_valid = B_TRUE;
				*slot_number =
				    PCIE_SLOTCAP_PHY_SLOT_NUM(slot_cap);

				/* Is PCI Express HotPlug capability set? */
				if (cdip &&
				    (slot_cap & PCIE_SLOTCAP_HP_CAPABLE)) {
					(void) ndi_prop_update_int(
					    DDI_DEV_T_NONE, cdip,
					    "pci-hotplug-type",
					    INBAND_HPC_PCIE);
				}
			}

			found_pciex = B_TRUE;
		}

		if (cdip && (cap == PCI_CAP_ID_PCI_HOTPLUG)) {
			(void) ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
			    "pci-hotplug-type", INBAND_HPC_SHPC);
		}

		capsp = (*pci_getb_func)(bus, dev, func,
		    capsp + PCI_CAP_NEXT_PTR);
	}

	return (found_pciex);
}