Пример #1
0
/*
 * pcmu_get_reg_set_size
 *
 * Given a dev info pointer to a pci child and a register number, this
 * routine returns the size element of that reg set property.
 *
 * used by: pcmu_ctlops() - DDI_CTLOPS_REGSIZE
 *
 * return value: size of reg set on success, zero on error
 */
off_t
pcmu_get_reg_set_size(dev_info_t *child, int rnumber)
{
	pci_regspec_t *pcmu_rp;
	off_t size;
	int i;

	if (rnumber < 0) {
		return (0);
	}

	/*
	 * Get the reg property for the device.
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
	    (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) {
		return (0);
	}

	if (rnumber >= (i / (int)sizeof (pci_regspec_t))) {
		kmem_free(pcmu_rp, i);
		return (0);
	}

	size = pcmu_rp[rnumber].pci_size_low |
		((uint64_t)pcmu_rp[rnumber].pci_size_hi << 32);
	kmem_free(pcmu_rp, i);
	return (size);
}
Пример #2
0
/*
 * search the entries of the "reg" property for one which has the desired
 * combination of phys_hi bits and contains the desired address.
 *
 * This version searches a ISA-style "reg" property.  It was prompted by
 * issues surrounding 8514/A support.  By IEEE 1275 compatibility conventions,
 * 8514/A registers should have been added after all standard VGA registers.
 * Unfortunately, the Solaris/Intel device configuration framework
 * (a) lists the 8514/A registers before the video memory, and then
 * (b) also sorts the entries so that I/O entries come before memory
 *     entries.
 *
 * It returns the "reg" index and offset into that register set.
 * The offset is needed because there exist (broken?) BIOSes that
 * report larger ranges enclosing the standard ranges.  One reports
 * 0x3bf for 0x21 instead of 0x3c0 for 0x20, for instance.  Using the
 * offset adjusts for this difference in the base of the register set.
 *
 * Note that this routine may not be fully general; it is intended for the
 * specific purpose of finding a couple of particular VGA reg entries and
 * may not be suitable for all reg-searching purposes.
 */
static int
vgatext_get_isa_reg_index(
	dev_info_t *const devi,
	unsigned long hival,
	unsigned long addr,
	off_t *offset)
{

	int		length, index;
	struct regspec	*reg;

	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
	    "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
		return (-1);
	}

	for (index = 0; index < length / sizeof (struct regspec); index++) {
		if (reg[index].regspec_bustype != hival)
			continue;
		if (reg[index].regspec_addr > addr)
			continue;
		if (reg[index].regspec_addr + reg[index].regspec_size <= addr)
			continue;

		*offset = addr - reg[index].regspec_addr;
		kmem_free(reg, (size_t)length);
		return (index);
	}
	kmem_free(reg, (size_t)length);

	return (-1);
}
Пример #3
0
static int
dr_is_real_device(dev_info_t *dip)
{
	struct regspec *regbuf = NULL;
	int length = 0;
	int rc;

	if (ddi_get_driver(dip) == NULL)
		return (0);

	if (DEVI(dip)->devi_pm_flags & (PMC_NEEDS_SR|PMC_PARENTAL_SR))
		return (1);
	if (DEVI(dip)->devi_pm_flags & PMC_NO_SR)
		return (0);

	/*
	 * now the general case
	 */
	rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
		(caddr_t)&regbuf, &length);
	ASSERT(rc != DDI_PROP_NO_MEMORY);
	if (rc != DDI_PROP_SUCCESS) {
		return (0);
	} else {
		if ((length > 0) && (regbuf != NULL))
			kmem_free(regbuf, length);
		return (1);
	}
}
Пример #4
0
/*
 * attach entry point:
 */
static int
isadma_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
	isadma_devstate_t *isadmap;	/* per isadma state pointer */
	int32_t instance;
	int ret = DDI_SUCCESS;

#ifdef DEBUG
	debug_print_level = 0;
	debug_info = 1;
#endif
	switch (cmd) {
	case DDI_ATTACH: {
		/*
		 * Allocate soft state for this instance.
		 */
		instance = ddi_get_instance(dip);
		if (ddi_soft_state_zalloc(per_isadma_state, instance)
				!= DDI_SUCCESS) {
			ret = DDI_FAILURE;
			goto exit;
		}
		isadmap = ddi_get_soft_state(per_isadma_state, instance);
		isadmap->isadma_dip = dip;

		/* Cache our register property */
		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
		    "reg", (caddr_t)&isadmap->isadma_regp,
		    &isadmap->isadma_reglen) != DDI_SUCCESS) {
			ret = DDI_FAILURE;
			goto fail_get_prop;
		}

		/* Initialize our mutex */
		mutex_init(&isadmap->isadma_access_lock, NULL, MUTEX_DRIVER,
		    NULL);

		/* Initialize our condition variable */
		cv_init(&isadmap->isadma_access_cv, NULL, CV_DRIVER, NULL);

		ddi_report_dev(dip);
		goto exit;

	}
	case DDI_RESUME:
	default:
		goto exit;
	}

fail_get_prop:
	ddi_soft_state_free(per_isadma_state, instance);

exit:
	return (ret);
}
Пример #5
0
/*ARGSUSED*/
static int
fco_getprop(dev_info_t *ap, fco_handle_t rp, fc_ci_t *cp)
{
	int proplen = -1;
	int flags = DDI_PROP_CANSLEEP;
	char *pnp, *bp;
	fc_phandle_t h;
	dev_info_t *dip;
	char propname[OBP_MAXPROPNAME];

	if (strstr(fc_cell2ptr(cp->svc_name), "inherited") == NULL)
		flags |= DDI_PROP_DONTPASS;

	if (fc_cell2int(cp->nargs) != 3)
		return (fc_syntax_error(cp, "nargs must be 3"));

	if (fc_cell2int(cp->nresults) < 1)
		return (fc_syntax_error(cp, "nresults must be > 0"));

	/*
	 * Make sure this is a handle we gave out ...
	 */
	h = fc_cell2phandle(fc_arg(cp, 0));
	if ((dip = fc_phandle_to_dip(fc_handle_to_phandle_head(rp), h)) == NULL)
		return (fc_priv_error(cp, "unknown handle"));

	/*
	 * XXX: We should care if the string is longer than OBP_MAXPROPNAME
	 */
	pnp = fc_cell2ptr(fc_arg(cp, 2));
	bzero(propname, OBP_MAXPROPNAME);
	if (copyinstr(pnp, propname, OBP_MAXPROPNAME - 1, NULL))
		return (fc_priv_error(cp, "EFAULT copying in propname"));

	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, flags,
	    propname, (caddr_t)&bp, &proplen))
		proplen = -1;

	if (proplen > 0) {
		char *up = fc_cell2ptr(fc_arg(cp, 1));
		int error;

		error = copyout(bp, up, proplen);
		kmem_free(bp, proplen);
		if (error)
			return (fc_priv_error(cp, "EFAULT copying data out"));
	}

	cp->nresults = fc_int2cell(1);
	fc_result(cp, 0) = fc_int2cell(proplen);
	return (fc_success_op(ap, rp, cp));
}
Пример #6
0
static int
ppb_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
    ddi_intr_handle_impl_t *hdlp, void *result)
{
	dev_info_t	*cdip = rdip;
	pci_regspec_t	*pci_rp;
	int		reglen, len;
	uint32_t	d, intr;

	if ((intr_op == DDI_INTROP_SUPPORTED_TYPES) ||
	    (hdlp->ih_type != DDI_INTR_TYPE_FIXED))
		goto done;

	/*
	 * If the interrupt-map property is defined at this
	 * node, it will have performed the interrupt
	 * translation as part of the property, so no
	 * rotation needs to be done.
	 */
	if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "interrupt-map", &len) == DDI_PROP_SUCCESS)
		goto done;

	cdip = get_my_childs_dip(dip, rdip);

	/*
	 * Use the devices reg property to determine its
	 * PCI bus number and device number.
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS,
	    "reg", (caddr_t)&pci_rp, &reglen) != DDI_SUCCESS)
		return (DDI_FAILURE);

	intr = hdlp->ih_vector;

	/* Spin the interrupt */
	d = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi);

	if ((intr >= PCI_INTA) && (intr <= PCI_INTD))
		hdlp->ih_vector = ((intr - 1 + (d % 4)) % 4 + 1);
	else
		cmn_err(CE_WARN, "%s%d: %s: PCI intr=%x out of range",
		    ddi_driver_name(rdip), ddi_get_instance(rdip),
		    ddi_driver_name(dip), intr);

	kmem_free(pci_rp, reglen);

done:
	/* Pass up the request to our parent. */
	return (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result));
}
Пример #7
0
/*
 * get_pcmu_properties
 *
 * This function is called from the attach routine to get the key
 * properties of the pci nodes.
 *
 * used by: pcmu_attach()
 *
 * return value: DDI_FAILURE on failure
 */
int
get_pcmu_properties(pcmu_t *pcmu_p, dev_info_t *dip)
{
	int i;

	/*
	 * Get the device's port id.
	 */
	if ((pcmu_p->pcmu_id = (uint32_t)pcmu_get_portid(dip)) == -1u) {
		cmn_err(CE_WARN, "%s%d: no portid property\n",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}

	/*
	 * Get the bus-ranges property.
	 */
	i = sizeof (pcmu_p->pcmu_bus_range);
	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "bus-range", (caddr_t)&pcmu_p->pcmu_bus_range, &i) != DDI_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: no bus-range property\n",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}
	PCMU_DBG2(PCMU_DBG_ATTACH, dip,
	    "get_pcmu_properties: bus-range (%x,%x)\n",
	    pcmu_p->pcmu_bus_range.lo, pcmu_p->pcmu_bus_range.hi);

	/*
	 * Get the ranges property.
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
	    (caddr_t)&pcmu_p->pcmu_ranges, &pcmu_p->pcmu_ranges_length) !=
	    DDI_SUCCESS) {
		cmn_err(CE_WARN, "%s%d: no ranges property\n",
		    ddi_driver_name(dip), ddi_get_instance(dip));
		return (DDI_FAILURE);
	}
	pcmu_fix_ranges(pcmu_p->pcmu_ranges,
	    pcmu_p->pcmu_ranges_length / sizeof (pcmu_ranges_t));

	/*
	 * Determine the number upa slot interrupts.
	 */
	pcmu_p->pcmu_numproxy = pcmu_get_numproxy(pcmu_p->pcmu_dip);
	PCMU_DBG1(PCMU_DBG_ATTACH, dip, "get_pcmu_properties: numproxy=%d\n",
	    pcmu_p->pcmu_numproxy);
	return (DDI_SUCCESS);
}
Пример #8
0
static int
pmubus_ctlops(dev_info_t *dip, dev_info_t *rdip,
    ddi_ctl_enum_t op, void *arg, void *result)
{
	dev_info_t *child = (dev_info_t *)arg;
	pmubus_obpregspec_t *pmubus_rp;
	char name[9];
	int reglen;

	switch (op) {
	case DDI_CTLOPS_INITCHILD:

		if (ddi_getlongprop(DDI_DEV_T_ANY, child,
		    DDI_PROP_DONTPASS, "reg", (caddr_t)&pmubus_rp,
		    &reglen) != DDI_SUCCESS) {

			return (DDI_FAILURE);
		}

		if ((reglen % sizeof (pmubus_obpregspec_t)) != 0) {
			cmn_err(CE_WARN,
			    "pmubus: reg property not well-formed for "
			    "%s size=%d\n", ddi_node_name(child), reglen);
			kmem_free(pmubus_rp, reglen);

			return (DDI_FAILURE);
		}
		(void) snprintf(name, sizeof (name), "%x,%x",
		    pmubus_rp->reg_addr_hi, pmubus_rp->reg_addr_lo);
		ddi_set_name_addr(child, name);
		kmem_free(pmubus_rp, reglen);

		return (DDI_SUCCESS);

	case DDI_CTLOPS_UNINITCHILD:

		ddi_set_name_addr(child, NULL);
		ddi_remove_minor_node(child, NULL);
		impl_rem_dev_props(child);

		return (DDI_SUCCESS);
	default:
		break;
	}

	return (ddi_ctlops(dip, rdip, op, arg, result));
}
Пример #9
0
/*
 * pcmu_get_nreg_set
 *
 * Given a dev info pointer to a pci child, this routine returns the
 * number of sets in its "reg" property.
 *
 * used by: pcmu_ctlops() - DDI_CTLOPS_NREGS
 *
 * return value: # of reg sets on success, zero on error
 */
uint_t
pcmu_get_nreg_set(dev_info_t *child)
{
	pci_regspec_t *pcmu_rp;
	int i, n;

	/*
	 * Get the reg property for the device.
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg",
	    (caddr_t)&pcmu_rp, &i) != DDI_SUCCESS) {
		return (0);
	}
	n = i / (int)sizeof (pci_regspec_t);
	kmem_free(pcmu_rp, i);
	return (n);
}
Пример #10
0
int
mii_sync(mii_handle_t mac, int phy)
{
	struct phydata *phyd = mac->phys[phy];
	int len, i, numprop;
	struct regprop {
		int reg;
		int value;
	} *regprop;

#ifdef MIIDEBUG
	if (miidebug & MIITRACE)
		cmn_err(CE_NOTE, "mii_sync (phy addr %d)", phy);
#endif

	len = 0;
	/*
	 * Conf file can specify a sequence of values to write to
	 * the PHY registers if required
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, mac->mii_dip,
	    DDI_PROP_DONTPASS, "phy-registers", (caddr_t)&regprop,
	    &len) == DDI_PROP_SUCCESS) {
		numprop = len / sizeof (struct regprop);
		for (i = 0; i < numprop; i++) {
			mac->mii_write(mac->mii_dip, phy,
			    regprop[i].reg, regprop[i].value);
#ifdef MIIDEBUG
			if (miidebug & MIITRACE)
				cmn_err(CE_NOTE, "PHY Write reg %d=%x",
				    regprop[i].reg, regprop[i].value);
#endif
		}
		kmem_free(regprop, len);
	} else {
		mac->mii_write(mac->mii_dip, phy, MII_CONTROL, phyd->control);
		if (phyd->phy_postreset)
			phyd->phy_postreset(mac, phy);
		if (phyd->fix_speed || phyd->fix_duplex) {
			/* XXX function return value ignored */
			(void) mii_fixspeed(mac, phy, phyd->fix_speed,
			    phyd->fix_duplex);
		}
	}
	return (MII_SUCCESS);
}
Пример #11
0
/*
 * pcmu_reloc_reg
 *
 * If the "reg" entry (*pcmu_rp) is relocatable, lookup "assigned-addresses"
 * property to fetch corresponding relocated address.
 *
 * used by: pcmu_map()
 *
 * return value:
 *
 *	DDI_SUCCESS		- on success
 *	DDI_ME_INVAL		- regspec is invalid
 */
int
pcmu_reloc_reg(dev_info_t *dip, dev_info_t *rdip, pcmu_t *pcmu_p,
	pci_regspec_t *rp)
{
	int assign_len, assign_entries, i;
	pci_regspec_t *assign_p;
	register uint32_t phys_hi = rp->pci_phys_hi;
	register uint32_t mask = PCI_REG_ADDR_M | PCI_CONF_ADDR_MASK;
	register uint32_t phys_addr = phys_hi & mask;

	PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip,
	    "\tpcmu_reloc_reg fr: %x.%x.%x %x.%x\n",
	    rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
	    rp->pci_size_hi, rp->pci_size_low);

	if ((phys_hi & PCI_RELOCAT_B) || !(phys_hi & PCI_ADDR_MASK)) {
		return (DDI_SUCCESS);
	}

	/* phys_mid must be 0 regardless space type. XXX-64 bit mem space */
	if (rp->pci_phys_mid != 0 || rp->pci_size_hi != 0) {
		PCMU_DBG0(PCMU_DBG_MAP | PCMU_DBG_CONT, pcmu_p->pcmu_dip,
		    "phys_mid or size_hi not 0\n");
		return (DDI_ME_INVAL);
	}

	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
	    "assigned-addresses", (caddr_t)&assign_p, &assign_len)) {
		return (DDI_ME_INVAL);
	}

	assign_entries = assign_len / sizeof (pci_regspec_t);
	for (i = 0; i < assign_entries; i++, assign_p++) {
		if ((assign_p->pci_phys_hi & mask) == phys_addr) {
			rp->pci_phys_low += assign_p->pci_phys_low;
			break;
		}
	}
	kmem_free(assign_p - i, assign_len);
	PCMU_DBG5(PCMU_DBG_MAP | PCMU_DBG_CONT, dip,
	    "\tpcmu_reloc_reg to: %x.%x.%x %x.%x\n",
	    rp->pci_phys_hi, rp->pci_phys_mid, rp->pci_phys_low,
	    rp->pci_size_hi, rp->pci_size_low);
	return (i < assign_entries ? DDI_SUCCESS : DDI_ME_INVAL);
}
Пример #12
0
/*
 * Return non-zero if device in tree is a PnP isa device
 */
static int
is_pnpisa(dev_info_t *dip)
{
	isa_regs_t *isa_regs;
	int proplen, pnpisa;

	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
	    (caddr_t)&isa_regs, &proplen) != DDI_PROP_SUCCESS) {
		return (0);
	}
	pnpisa = isa_regs[0].phys_hi & 0x80000000;
	/*
	 * free the memory allocated by ddi_getlongprop().
	 */
	kmem_free(isa_regs, proplen);
	if (pnpisa)
		return (1);
	else
		return (0);
}
Пример #13
0
static int
acebus_get_ranges_prop(ebus_devstate_t *ebus_p)
{
	struct ebus_pci_rangespec *rangep;
	int nrange, range_len;

	if (ddi_getlongprop(DDI_DEV_T_ANY, ebus_p->dip, DDI_PROP_DONTPASS,
	    "ranges", (caddr_t)&rangep, &range_len) != DDI_SUCCESS) {

		cmn_err(CE_WARN, "%s%d: can't get ranges property",
		    ddi_get_name(ebus_p->dip), ddi_get_instance(ebus_p->dip));
		return (DDI_ME_REGSPEC_RANGE);
	}

	nrange = range_len / sizeof (struct ebus_pci_rangespec);

	if (nrange == 0)  {
		kmem_free(rangep, range_len);
		return (DDI_FAILURE);
	}

#ifdef	DEBUG
	{
		int i;

		for (i = 0; i < nrange; i++) {
			DBG5(D_MAP, ebus_p,
			    "ebus range addr 0x%x.0x%x PCI range "
			    "addr 0x%x.0x%x.0x%x ", rangep[i].ebus_phys_hi,
			    rangep[i].ebus_phys_low, rangep[i].pci_phys_hi,
			    rangep[i].pci_phys_mid, rangep[i].pci_phys_low);
			DBG1(D_MAP, ebus_p, "Size 0x%x\n", rangep[i].rng_size);
		}
	}
#endif /* DEBUG */

	ebus_p->rangep = rangep;
	ebus_p->range_cnt = nrange;

	return (DDI_SUCCESS);
}
Пример #14
0
/*ARGSUSED*/
int
drm_get_pci_index_reg(dev_info_t *devi, uint_t physical, uint_t size,
    off_t *off)
{
	int		length;
	pci_regspec_t	*regs;
	int		n_reg, i;
	int		regnum;
	uint_t		base, regsize;

	regnum = -1;

	if (ddi_dev_nregs(devi, &n_reg) == DDI_FAILURE) {
		DRM_ERROR("drm_get_pci_index_reg:ddi_dev_nregs failed\n");
		n_reg = 0;
		return (-1);
	}

	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
	    "assigned-addresses", (caddr_t)&regs, &length) !=
	    DDI_PROP_SUCCESS) {
		DRM_ERROR("drm_get_pci_index_reg: ddi_getlongprop failed!\n");
		goto error;
	}

	for (i = 0; i < n_reg; i ++) {
		base = (uint_t)regs[i].pci_phys_low;
		regsize = (uint_t)regs[i].pci_size_low;
		if ((uint_t)physical >= base &&
		    (uint_t)physical < (base + regsize)) {
			regnum = i + 1;
			*off = (off_t)(physical - base);
			break;
		}
	}
	kmem_free(regs, (size_t)length);
	return (regnum);
error:
	kmem_free(regs, (size_t)length);
	return (-1);
}
Пример #15
0
int
drm_get_pci_index_reg(dev_info_t *dip, uint_t paddr, uint_t size, off_t *off)
{
    pci_regspec_t *regs = NULL;
    int len;
    uint_t regbase, regsize;
    int nregs, i;
    int regnum;

    regnum = -1;

    if (ddi_dev_nregs(dip, &nregs) == DDI_FAILURE) {
        DRM_ERROR("ddi_dev_nregs() failed");
        return (-1);
    }

    if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
                        "assigned-addresses", (caddr_t)&regs, &len) != DDI_PROP_SUCCESS) {
        DRM_ERROR("ddi_getlongprop() failed");
        if (regs)
            kmem_free(regs, (size_t)len);
        return (-1);
    }

    for (i = 0; i < nregs; i ++) {
        regbase = (uint_t)regs[i].pci_phys_low;
        regsize = (uint_t)regs[i].pci_size_low;
        if ((uint_t)paddr >= regbase &&
                (uint_t)paddr < (regbase + regsize)) {
            regnum = i + 1;
            *off = (off_t)(paddr - regbase);
            break;
        }
    }

    kmem_free(regs, (size_t)len);
    return (regnum);
}
Пример #16
0
/*
 * search the entries of the "reg" property for one which has the desired
 * combination of phys_hi bits and contains the desired address.
 *
 * This version searches a PCI-style "reg" property.  It was prompted by
 * issues surrounding the presence or absence of an entry for the ROM:
 * (a) a transition problem with PowerPC Virtual Open Firmware
 * (b) uncertainty as to whether an entry will be included on a device
 *     with ROM support (and so an "active" ROM base address register),
 *     but no ROM actually installed.
 *
 * See the note below on vgatext_get_isa_reg_index for the reasons for
 * returning the offset.
 *
 * Note that this routine may not be fully general; it is intended for the
 * specific purpose of finding a couple of particular VGA reg entries and
 * may not be suitable for all reg-searching purposes.
 */
static int
vgatext_get_pci_reg_index(
	dev_info_t *const devi,
	unsigned long himask,
	unsigned long hival,
	unsigned long addr,
	off_t *offset)
{

	int			length, index;
	pci_regspec_t	*reg;

	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
	    "reg", (caddr_t)&reg, &length) != DDI_PROP_SUCCESS) {
		return (-1);
	}

	for (index = 0; index < length / sizeof (pci_regspec_t); index++) {
		if ((reg[index].pci_phys_hi & himask) != hival)
			continue;
		if (reg[index].pci_size_hi != 0)
			continue;
		if (reg[index].pci_phys_mid != 0)
			continue;
		if (reg[index].pci_phys_low > addr)
			continue;
		if (reg[index].pci_phys_low + reg[index].pci_size_low <= addr)
			continue;

		*offset = addr - reg[index].pci_phys_low;
		kmem_free(reg, (size_t)length);
		return (index);
	}
	kmem_free(reg, (size_t)length);

	return (-1);
}
Пример #17
0
/*
 * vdds_release_range_prop -- cleanups an entry in the ranges property
 *	corresponding to a cookie.
 */
static void
vdds_release_range_prop(dev_info_t *nexus_dip, uint64_t cookie)
{
	vdds_ranges_t *prng;
	vdds_ranges_t *prp;
	int prnglen;
	int nrng;
	int rnum;
	boolean_t success = B_FALSE;
	int rv;

	if ((rv = ddi_getlongprop(DDI_DEV_T_ANY, nexus_dip, DDI_PROP_DONTPASS,
	    "ranges", (caddr_t)&prng, &prnglen)) != DDI_SUCCESS) {
		DERR(NULL,
		    "Failed to get nexus ranges property(dip=0x%p) rv=%d",
		    nexus_dip, rv);
		return;
	}
	nrng = prnglen/(sizeof (vdds_ranges_t));
	for (rnum = 0; rnum < nrng; rnum++) {
		prp = &prng[rnum];
		if (prp->child_hi == HVCOOKIE(cookie)) {
			prp->child_hi = 0;
			success = B_TRUE;
			break;
		}
	}
	if (success) {
		if (ndi_prop_update_int_array(DDI_DEV_T_NONE, nexus_dip,
		    "ranges", (int *)prng, (nrng * 6)) != DDI_SUCCESS) {
			DERR(NULL,
			    "Failed to update nexus ranges prop(dip=0x%p)",
			    nexus_dip);
		}
	}
}
Пример #18
0
/*
 * bus map entry point:
 *
 * 	if map request is for an rnumber
 *		get the corresponding regspec from device node
 * 	build a new regspec in our parent's format
 *	build a new map_req with the new regspec
 *	call up the tree to complete the mapping
 */
int
px_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
	off_t off, off_t len, caddr_t *addrp)
{
	px_t *px_p = DIP_TO_STATE(dip);
	struct regspec p_regspec;
	ddi_map_req_t p_mapreq;
	int reglen, rval, r_no;
	pci_regspec_t reloc_reg, *rp = &reloc_reg;

	DBG(DBG_MAP, dip, "rdip=%s%d:",
	    ddi_driver_name(rdip), ddi_get_instance(rdip));

	if (mp->map_flags & DDI_MF_USER_MAPPING)
		return (DDI_ME_UNIMPLEMENTED);

	switch (mp->map_type) {
	case DDI_MT_REGSPEC:
		reloc_reg = *(pci_regspec_t *)mp->map_obj.rp;	/* dup whole */
		break;

	case DDI_MT_RNUMBER:
		r_no = mp->map_obj.rnumber;
		DBG(DBG_MAP | DBG_CONT, dip, " r#=%x", r_no);

		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
		    "reg", (caddr_t)&rp, &reglen) != DDI_SUCCESS)
			return (DDI_ME_RNUMBER_RANGE);

		if (r_no < 0 || r_no >= reglen / sizeof (pci_regspec_t)) {
			kmem_free(rp, reglen);
			return (DDI_ME_RNUMBER_RANGE);
		}
		rp += r_no;
		break;

	default:
		return (DDI_ME_INVAL);
	}
	DBG(DBG_MAP | DBG_CONT, dip, "\n");

	if ((rp->pci_phys_hi & PCI_REG_ADDR_M) == PCI_ADDR_CONFIG) {
		/*
		 * There may be a need to differentiate between PCI
		 * and PCI-Ex devices so the following range check is
		 * done correctly, depending on the implementation of
		 * pcieb bridge nexus driver.
		 */
		if ((off >= PCIE_CONF_HDR_SIZE) ||
		    (len > PCIE_CONF_HDR_SIZE) ||
		    (off + len > PCIE_CONF_HDR_SIZE))
			return (DDI_ME_INVAL);
		/*
		 * the following function returning a DDI_FAILURE assumes
		 * that there are no virtual config space access services
		 * defined in this layer. Otherwise it is availed right
		 * here and we return.
		 */
		rval = px_lib_map_vconfig(dip, mp, off, rp, addrp);
		if (rval == DDI_SUCCESS)
			goto done;
	}

	/*
	 * No virtual config space services or we are mapping
	 * a region of memory mapped config/IO/memory space, so proceed
	 * to the parent.
	 */

	/* relocate within 64-bit pci space through "assigned-addresses" */
	if (rval = px_reloc_reg(dip, rdip, px_p, rp))
		goto done;

	if (len)	/* adjust regspec according to mapping request */
		rp->pci_size_low = len;	/* MIN ? */
	rp->pci_phys_low += off;

	/* translate relocated pci regspec into parent space through "ranges" */
	if (rval = px_xlate_reg(px_p, rp, &p_regspec))
		goto done;

	p_mapreq = *mp;		/* dup the whole structure */
	p_mapreq.map_type = DDI_MT_REGSPEC;
	p_mapreq.map_obj.rp = &p_regspec;
	px_lib_map_attr_check(&p_mapreq);
	rval = ddi_map(dip, &p_mapreq, 0, 0, addrp);

	if (rval == DDI_SUCCESS) {
		/*
		 * Set-up access functions for FM access error capable drivers.
		 */
		if (DDI_FM_ACC_ERR_CAP(ddi_fm_capable(rdip)))
			px_fm_acc_setup(mp, rdip, rp);
	}

done:
	if (mp->map_type == DDI_MT_RNUMBER)
		kmem_free(rp - r_no, reglen);

	return (rval);
}
Пример #19
0
/*ARGSUSED*/
static int
ppb_ctlops(dev_info_t *dip, dev_info_t *rdip,
	ddi_ctl_enum_t ctlop, void *arg, void *result)
{
	pci_regspec_t *drv_regp;
	int	reglen;
	int	rn;
	int	totreg;
	ppb_devstate_t *ppb = ddi_get_soft_state(ppb_state,
	    ddi_get_instance(dip));
	struct detachspec *dsp;
	struct attachspec *asp;

	switch (ctlop) {
	case DDI_CTLOPS_REPORTDEV:
		if (rdip == (dev_info_t *)0)
			return (DDI_FAILURE);
		cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
		    ddi_driver_name(rdip),
		    ddi_get_instance(rdip));
		return (DDI_SUCCESS);

	case DDI_CTLOPS_INITCHILD:
		return (ppb_initchild((dev_info_t *)arg));

	case DDI_CTLOPS_UNINITCHILD:
		ppb_removechild((dev_info_t *)arg);
		return (DDI_SUCCESS);

	case DDI_CTLOPS_SIDDEV:
		return (DDI_SUCCESS);

	case DDI_CTLOPS_REGSIZE:
	case DDI_CTLOPS_NREGS:
		if (rdip == (dev_info_t *)0)
			return (DDI_FAILURE);
		break;

	/* X86 systems support PME wakeup from suspend */
	case DDI_CTLOPS_ATTACH:
		if (!pcie_is_child(dip, rdip))
			return (DDI_SUCCESS);

		asp = (struct attachspec *)arg;
		if ((ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
		    (asp->when == DDI_POST) && (asp->result == DDI_SUCCESS))
			pf_init(rdip, (void *)ppb->ppb_fm_ibc, asp->cmd);

		if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE)
			if (pci_pre_resume(rdip) != DDI_SUCCESS)
				return (DDI_FAILURE);

		return (DDI_SUCCESS);

	case DDI_CTLOPS_DETACH:
		if (!pcie_is_child(dip, rdip))
			return (DDI_SUCCESS);

		dsp = (struct detachspec *)arg;
		if ((ppb->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
		    (dsp->when == DDI_PRE))
			pf_fini(rdip, dsp->cmd);

		if (dsp->cmd == DDI_SUSPEND && dsp->when == DDI_POST)
			if (pci_post_suspend(rdip) != DDI_SUCCESS)
				return (DDI_FAILURE);

		return (DDI_SUCCESS);

	case DDI_CTLOPS_PEEK:
	case DDI_CTLOPS_POKE:
		if (strcmp(ddi_driver_name(ddi_get_parent(dip)), "npe") != 0)
			return (ddi_ctlops(dip, rdip, ctlop, arg, result));
		return (pci_peekpoke_check(dip, rdip, ctlop, arg, result,
		    ddi_ctlops, &ppb->ppb_err_mutex,
		    &ppb->ppb_peek_poke_mutex, ppb_peekpoke_cb));

	default:
		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
	}

	*(int *)result = 0;
	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip,
	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
	    (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
		return (DDI_FAILURE);

	totreg = reglen / sizeof (pci_regspec_t);
	if (ctlop == DDI_CTLOPS_NREGS)
		*(int *)result = totreg;
	else if (ctlop == DDI_CTLOPS_REGSIZE) {
		rn = *(int *)arg;
		if (rn >= totreg) {
			kmem_free(drv_regp, reglen);
			return (DDI_FAILURE);
		}
		*(off_t *)result = drv_regp[rn].pci_size_low;
	}

	kmem_free(drv_regp, reglen);
	return (DDI_SUCCESS);
}
Пример #20
0
/*
 * The isadma_map routine determines if it's child is attempting to map a
 * shared reg.  If it is, it installs it's own vectors and bus private pointer
 * and stacks those ops that were already defined.
 */
static int
isadma_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
	off_t off, off_t len, caddr_t *addrp)
{
	isadma_devstate_t *isadmap = ddi_get_soft_state(per_isadma_state,
	    ddi_get_instance(dip));
	dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
	ebus_regspec_t *child_regp, *regp;
	int32_t rnumber = mp->map_obj.rnumber;
	int32_t reglen;
	int ret;
	ddi_acc_impl_t *hp;

	/*
	 * Get child regspec since the mapping struct may not have it yet
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
	    "reg", (caddr_t)&regp, &reglen) != DDI_SUCCESS) {
		return (DDI_FAILURE);
	}

	child_regp = regp + rnumber;

	DPRINTF(ISADMA_MAP_DEBUG, ("isadma_map: child regp %p "
	    "parent regp %p Child reg array %p\n", child_regp,
	    isadmap->isadma_regp, regp));

	/* Figure out if we're mapping or unmapping */
	switch (mp->map_op) {
	case DDI_MO_MAP_LOCKED:
		/* Call up device tree to establish mapping */
		ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
		    (pdip, rdip, mp, off, len, addrp);

		if ((ret != DDI_SUCCESS) ||
		    !IS_SAME_REG(child_regp, isadmap->isadma_regp))
			break;

		/* Post-process the mapping request. */
		hp = kmem_alloc(sizeof (ddi_acc_impl_t), KM_SLEEP);
		*hp = *(ddi_acc_impl_t *)mp->map_handlep;
		impl_acc_hdl_get((ddi_acc_handle_t)mp->map_handlep)->
		    ah_platform_private = hp;
		hp = (ddi_acc_impl_t *)mp->map_handlep;
		hp->ahi_common.ah_bus_private = isadmap;
		hp->ahi_get8 = isadma_get8;
		hp->ahi_get16 = isadma_get16;
		hp->ahi_get32 = isadma_noget32;
		hp->ahi_get64 = isadma_noget64;
		hp->ahi_put8 = isadma_put8;
		hp->ahi_put16 = isadma_put16;
		hp->ahi_put32 = isadma_noput32;
		hp->ahi_put64 = isadma_noput64;
		hp->ahi_rep_get8 = isadma_norep_get8;
		hp->ahi_rep_get16 = isadma_norep_get16;
		hp->ahi_rep_get32 = isadma_norep_get32;
		hp->ahi_rep_get64 = isadma_norep_get64;
		hp->ahi_rep_put8 = isadma_norep_put8;
		hp->ahi_rep_put16 = isadma_norep_put16;
		hp->ahi_rep_put32 = isadma_norep_put32;
		hp->ahi_rep_put64 = isadma_norep_put64;
		break;

	case DDI_MO_UNMAP:
		if (IS_SAME_REG(child_regp, isadmap->isadma_regp)) {
			hp = impl_acc_hdl_get(
			    (ddi_acc_handle_t)mp->map_handlep)->
			    ah_platform_private;
			*(ddi_acc_impl_t *)mp->map_handlep = *hp;
			kmem_free(hp, sizeof (ddi_acc_impl_t));
		}

		/* Call up tree to tear down mapping */
		ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
			(pdip, rdip, mp, off, len, addrp);
		break;

	default:
		ret = DDI_FAILURE;
		break;
	}

	kmem_free(regp, reglen);
	return (ret);
}
Пример #21
0
/*
 * The pmubus_map routine determines if it's child is attempting to map a
 * shared reg.  If it is, it installs it's own vectors and bus private pointer.
 */
static int
pmubus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
	off_t off, off_t len, caddr_t *addrp)
{
	pmubus_devstate_t *pmubusp = ddi_get_soft_state(per_pmubus_state,
	    ddi_get_instance(dip));
	dev_info_t *pdip = (dev_info_t *)DEVI(dip)->devi_parent;
	pmubus_regspec_t pmubus_rp;
	pmubus_obpregspec_t *pmubus_regs = NULL;
	int pmubus_regs_size;
	uint64_t *pmubus_regmask = NULL;
	int pmubus_regmask_size;
	pci_regspec_t pci_reg;
	int32_t rnumber = mp->map_obj.rnumber;
	pmubus_mapreq_t *pmubus_mapreqp;
	int ret = DDI_SUCCESS;
	char *map_fail1 = "Map Type Unknown";
	char *map_fail2 = "DDI_MT_REGSPEC";
	char *s = map_fail1;

	*addrp = NULL;

	/*
	 * Handle the mapping according to its type.
	 */
	DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: off=%lx len=%lx\n",
	    ddi_get_name(rdip), ddi_get_instance(rdip), off, len));
	switch (mp->map_type) {
	case DDI_MT_RNUMBER: {
		int n;

		/*
		 * Get the "reg" property from the device node and convert
		 * it to our parent's format.
		 */
		rnumber = mp->map_obj.rnumber;
		DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: rnumber=%x "
		    "handlep=%p\n", ddi_get_name(rdip), ddi_get_instance(rdip),
		    rnumber, (void *)mp->map_handlep));

		if (ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
		    "reg", (caddr_t)&pmubus_regs, &pmubus_regs_size) !=
		    DDI_SUCCESS) {
			DPRINTF(PMUBUS_MAP_DEBUG, ("can't get reg "
			    "property\n"));
			ret = DDI_ME_RNUMBER_RANGE;
			goto done;
		}
		n = pmubus_regs_size / sizeof (pmubus_obpregspec_t);

		if (rnumber < 0 || rnumber >= n) {
			DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber out of range\n"));
			ret = DDI_ME_RNUMBER_RANGE;
			goto done;
		}

		pmubus_rp.reg_addr = ((uint64_t)
		    pmubus_regs[rnumber].reg_addr_hi << 32) |
		    (uint64_t)pmubus_regs[rnumber].reg_addr_lo;
		pmubus_rp.reg_size = pmubus_regs[rnumber].reg_size;

		(void) ddi_getlongprop(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS,
		    "register-mask", (caddr_t)&pmubus_regmask,
		    &pmubus_regmask_size);

		/* Create our own mapping private structure */
		break;

	}
	case DDI_MT_REGSPEC:
		/*
		 * This bus has no bus children that have to map in an address
		 * space, so we can assume that we'll never see an
		 * DDI_MT_REGSPEC request
		 */
		s = map_fail2;
		ret = DDI_ME_REGSPEC_RANGE;
		/*FALLTHROUGH*/

	default:
		if (ret == DDI_SUCCESS)
			ret = DDI_ME_INVAL;
		DPRINTF(PMUBUS_MAP_DEBUG, ("rdip=%s%d: pmubus_map: "
		    "%s is an invalid map type.\nmap request handlep=0x%p\n",
		    ddi_get_name(rdip), ddi_get_instance(rdip), s, (void *)mp));

		ret = DDI_ME_RNUMBER_RANGE;
		goto done;
	}

	/* Adjust our reg property with offset and length */
	if ((pmubus_rp.reg_addr + off) >
	    (pmubus_rp.reg_addr + pmubus_rp.reg_size)) {
		ret = DDI_ME_INVAL;
		goto done;
	}

	pmubus_rp.reg_addr += off;
	if (len && (len < pmubus_rp.reg_size))
		pmubus_rp.reg_size = len;

	/* Translate our child regspec into our parents address domain */
	ret = pmubus_apply_range(pmubusp, rdip, &pmubus_rp, &pci_reg);

	/* Check if the apply range failed */
	if (ret < DDI_SUCCESS)
		goto done;

	/*
	 * If our childs xlated address falls into our shared address range,
	 * setup our mapping handle.
	 */
	if (ret > DDI_SUCCESS) {
		/* Figure out if we're mapping or unmapping */
		switch (mp->map_op) {
		case DDI_MO_MAP_LOCKED: {
			ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep;

			pmubus_mapreqp = kmem_alloc(sizeof (*pmubus_mapreqp),
			    KM_SLEEP);

			pmubus_mapreqp->mapreq_flags = ret;
			pmubus_mapreqp->mapreq_softsp = pmubusp;
			pmubus_mapreqp->mapreq_addr = pmubus_rp.reg_addr;
			pmubus_mapreqp->mapreq_size = pmubus_rp.reg_size;

			if (ret & MAPREQ_SHARED_BITS) {
				pmubus_mapreqp->mapreq_mask =
				    pmubus_mask(pmubus_regs, rnumber,
				    pmubus_regmask);
				DPRINTF(PMUBUS_MAP_DEBUG, ("rnumber=%d "
				    "mask=%lx\n", rnumber,
				    pmubus_mapreqp->mapreq_mask));
				if (pmubus_mapreqp->mapreq_mask == 0) {
					kmem_free(pmubus_mapreqp,
					    sizeof (pmubus_mapreq_t));
					ret = DDI_ME_INVAL;
					break;
				}
			}

			hp->ahi_common.ah_bus_private = pmubus_mapreqp;

			/* Initialize the access vectors */
			hp->ahi_get8 = pmubus_get8;
			hp->ahi_get16 = pmubus_noget16;
			hp->ahi_get32 = pmubus_get32;
			hp->ahi_get64 = pmubus_noget64;
			hp->ahi_put8 = pmubus_put8;
			hp->ahi_put16 = pmubus_noput16;
			hp->ahi_put32 = pmubus_put32;
			hp->ahi_put64 = pmubus_noput64;
			hp->ahi_rep_get8 = pmubus_norep_get8;
			hp->ahi_rep_get16 = pmubus_norep_get16;
			hp->ahi_rep_get32 = pmubus_norep_get32;
			hp->ahi_rep_get64 = pmubus_norep_get64;
			hp->ahi_rep_put8 = pmubus_norep_put8;
			hp->ahi_rep_put16 = pmubus_norep_put16;
			hp->ahi_rep_put32 = pmubus_norep_put32;
			hp->ahi_rep_put64 = pmubus_norep_put64;

			ret = DDI_SUCCESS;
			break;
		}

		case DDI_MO_UNMAP: {
			ddi_acc_impl_t *hp = (ddi_acc_impl_t *)mp->map_handlep;

			pmubus_mapreqp = hp->ahi_common.ah_bus_private;

			/* Free the our map request struct */
			kmem_free(pmubus_mapreqp, sizeof (pmubus_mapreq_t));

			ret = DDI_SUCCESS;
			break;
		}

		default:
			ret = DDI_ME_UNSUPPORTED;
		}
	} else {
		/* Prepare the map request struct for a call to our parent */
		mp->map_type = DDI_MT_REGSPEC;
		mp->map_obj.rp = (struct regspec *)&pci_reg;

		/* Pass the mapping operation up the device tree */
		ret = (DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)
		    (pdip, rdip, mp, off, len, addrp);
	}

done:
	if (pmubus_regs != NULL)
		kmem_free(pmubus_regs, pmubus_regs_size);
	if (pmubus_regmask != NULL)
		kmem_free(pmubus_regmask, pmubus_regmask_size);
	return (ret);
}
Пример #22
0
/*
 * attach entry point:
 *
 * normal attach:
 *
 *	create soft state structure (dip, reg, nreg and state fields)
 *	map in configuration header
 *	make sure device is properly configured
 *	report device
 */
static int
pmubus_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
	pmubus_devstate_t *pmubusp;	/* per pmubus state pointer */
	int32_t instance;

	switch (cmd) {
	case DDI_ATTACH:
		/*
		 * Allocate soft state for this instance.
		 */
		instance = ddi_get_instance(dip);
		if (ddi_soft_state_zalloc(per_pmubus_state, instance) !=
		    DDI_SUCCESS) {
			cmn_err(CE_WARN, "pmubus_attach: Can't allocate soft "
			    "state.\n");
			goto fail_exit;
		}

		pmubusp = ddi_get_soft_state(per_pmubus_state, instance);
		pmubusp->pmubus_dip = dip;

		/* Cache our register property */
		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
		    "reg", (caddr_t)&pmubusp->pmubus_regp,
		    &pmubusp->pmubus_reglen) != DDI_SUCCESS) {
			cmn_err(CE_WARN, "pmubus_attach: Can't acquire reg "
			    "property.\n");
			goto fail_get_regs;
		}

		/* Cache our ranges property */
		if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
		    "ranges", (caddr_t)&pmubusp->pmubus_rangep,
		    &pmubusp->pmubus_rnglen) != DDI_SUCCESS) {
			cmn_err(CE_WARN, "pmubus_attach: Can't acquire the "
			    "ranges property.\n");
			goto fail_get_ranges;

		}

		/* Calculate the number of ranges */
		pmubusp->pmubus_nranges =
		    pmubusp->pmubus_rnglen / sizeof (pmu_rangespec_t);

		/* Set up the mapping to our registers */
		if (pci_config_setup(dip, &pmubusp->pmubus_reghdl) !=
		    DDI_SUCCESS) {
			cmn_err(CE_WARN, "pmubus_attach: Can't map in "
			    "register space.\n");
			goto fail_map_regs;
		}

		/* Initialize our register access mutex */
		mutex_init(&pmubusp->pmubus_reg_access_lock, NULL,
		    MUTEX_DRIVER, NULL);

		ddi_report_dev(dip);
		return (DDI_SUCCESS);

	case DDI_RESUME:
		return (DDI_SUCCESS);
	}

fail_map_regs:
	kmem_free(pmubusp->pmubus_rangep, pmubusp->pmubus_rnglen);

fail_get_ranges:
	kmem_free(pmubusp->pmubus_regp, pmubusp->pmubus_reglen);

fail_get_regs:
	ddi_soft_state_free(per_pmubus_state, instance);

fail_exit:
	return (DDI_FAILURE);
}
Пример #23
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);
}
Пример #24
0
/*ARGSUSED*/
static int
ppb_ctlops(dev_info_t *dip, dev_info_t *rdip,
	ddi_ctl_enum_t ctlop, void *arg, void *result)
{
	pci_regspec_t *drv_regp;
	int	reglen;
	int	rn;
	struct	attachspec *as;
	struct	detachspec *ds;
	int	totreg;
	ppb_devstate_t *ppb_p;

	ppb_p = (ppb_devstate_t *)ddi_get_soft_state(ppb_state,
	    ddi_get_instance(dip));

	switch (ctlop) {
	case DDI_CTLOPS_REPORTDEV:
		if (rdip == (dev_info_t *)0)
			return (DDI_FAILURE);
		cmn_err(CE_CONT, "?PCI-device: %s@%s, %s%d\n",
		    ddi_node_name(rdip), ddi_get_name_addr(rdip),
		    ddi_driver_name(rdip),
		    ddi_get_instance(rdip));
		return (DDI_SUCCESS);

	case DDI_CTLOPS_INITCHILD:
		return (ppb_initchild((dev_info_t *)arg));

	case DDI_CTLOPS_UNINITCHILD:
		ppb_uninitchild((dev_info_t *)arg);
		return (DDI_SUCCESS);

	case DDI_CTLOPS_ATTACH:
		if (!pcie_is_child(dip, rdip))
			return (DDI_SUCCESS);

		as = (struct attachspec *)arg;
		if ((ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
		    (as->when == DDI_POST) && (as->result == DDI_SUCCESS))
			pf_init(rdip, ppb_p->fm_ibc, as->cmd);

		return (DDI_SUCCESS);

	case DDI_CTLOPS_DETACH:
		if (!pcie_is_child(dip, rdip))
			return (DDI_SUCCESS);

		ds = (struct detachspec *)arg;
		if ((ppb_p->parent_bus == PCIE_PCIECAP_DEV_TYPE_PCIE_DEV) &&
		    (ds->when == DDI_PRE))
			pf_fini(rdip, ds->cmd);

		return (DDI_SUCCESS);

	case DDI_CTLOPS_SIDDEV:
		return (DDI_SUCCESS);

	case DDI_CTLOPS_REGSIZE:
	case DDI_CTLOPS_NREGS:
		if (rdip == (dev_info_t *)0)
			return (DDI_FAILURE);
		break;
	default:
		return (ddi_ctlops(dip, rdip, ctlop, arg, result));
	}

	*(int *)result = 0;
	if (ddi_getlongprop(DDI_DEV_T_ANY, rdip,
	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "reg",
	    (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
		return (DDI_FAILURE);

	totreg = reglen / sizeof (pci_regspec_t);
	if (ctlop == DDI_CTLOPS_NREGS)
		*(int *)result = totreg;
	else if (ctlop == DDI_CTLOPS_REGSIZE) {
		rn = *(int *)arg;
		if (rn >= totreg) {
			kmem_free(drv_regp, reglen);
			return (DDI_FAILURE);
		}
		*(off_t *)result = drv_regp[rn].pci_size_low |
		    ((uint64_t)drv_regp[rn].pci_size_hi << 32);
	}

	kmem_free(drv_regp, reglen);
	return (DDI_SUCCESS);
}
Пример #25
0
/* ARGSUSED */
static int
ptemopen(
	queue_t    *q,		/* pointer to the read side queue */
	dev_t   *devp,		/* pointer to stream tail's dev */
	int	oflag,		/* the user open(2) supplied flags */
	int	sflag,		/* open state flag */
	cred_t *credp)		/* credentials */
{
	struct ptem *ntp;	/* ptem entry for this PTEM module */
	mblk_t *mop;		/* an setopts mblk */
	struct stroptions *sop;
	struct termios *termiosp;
	int len;

	if (sflag != MODOPEN)
		return (EINVAL);

	if (q->q_ptr != NULL) {
		/* It's already attached. */
		return (0);
	}

	/*
	 * Allocate state structure.
	 */
	ntp = kmem_alloc(sizeof (*ntp), KM_SLEEP);

	/*
	 * Allocate a message block, used to pass the zero length message for
	 * "stty 0".
	 *
	 * NOTE: it's better to find out if such a message block can be
	 *	 allocated before it's needed than to not be able to
	 *	 deliver (for possible lack of buffers) when a hang-up
	 *	 occurs.
	 */
	if ((ntp->dack_ptr = allocb(4, BPRI_MED)) == NULL) {
		kmem_free(ntp, sizeof (*ntp));
		return (EAGAIN);
	}

	/*
	 * Initialize an M_SETOPTS message to set up hi/lo water marks on
	 * stream head read queue and add controlling tty if not set.
	 */
	mop = allocb(sizeof (struct stroptions), BPRI_MED);
	if (mop == NULL) {
		freemsg(ntp->dack_ptr);
		kmem_free(ntp, sizeof (*ntp));
		return (EAGAIN);
	}
	mop->b_datap->db_type = M_SETOPTS;
	mop->b_wptr += sizeof (struct stroptions);
	sop = (struct stroptions *)mop->b_rptr;
	sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
	sop->so_hiwat = 512;
	sop->so_lowat = 256;

	/*
	 * Cross-link.
	 */
	ntp->q_ptr = q;
	q->q_ptr = ntp;
	WR(q)->q_ptr = ntp;

	/*
	 * Get termios defaults.  These are stored as
	 * a property in the "options" node.
	 */
	if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), 0, "ttymodes",
	    (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
	    len == sizeof (struct termios)) {

		ntp->cflags = termiosp->c_cflag;
		kmem_free(termiosp, len);
	} else {
		/*
		 * Gack!  Whine about it.
		 */
		cmn_err(CE_WARN, "ptem: Couldn't get ttymodes property!");
	}
	ntp->wsz.ws_row = 0;
	ntp->wsz.ws_col = 0;
	ntp->wsz.ws_xpixel = 0;
	ntp->wsz.ws_ypixel = 0;

	ntp->state = 0;

	/*
	 * Commit to the open and send the M_SETOPTS off to the stream head.
	 */
	qprocson(q);
	putnext(q, mop);

	return (0);
}
Пример #26
0
/*ARGSUSED*/
static int
isa_apply_range(dev_info_t *dip, struct regspec *isa_reg_p,
    pci_regspec_t *pci_reg_p)
{
	pib_ranges_t *ranges, *rng_p;
	int len, i, offset, nrange;

	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
	    "ranges", (caddr_t)&ranges, &len) != DDI_SUCCESS) {
		cmn_err(CE_WARN, "Can't get %s ranges property",
		    ddi_get_name(dip));
		return (DDI_ME_REGSPEC_RANGE);
	}
	nrange = len / sizeof (pib_ranges_t);
	rng_p = ranges;
	for (i = 0; i < nrange; i++, rng_p++) {
		/* Check for correct space */
		if (isa_reg_p->regspec_bustype != rng_p->child_high)
			continue;

		/* Detect whether request entirely fits within a range */
		if (isa_reg_p->regspec_addr < rng_p->child_low)
			continue;
		if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size - 1) >
		    (rng_p->child_low + rng_p->size - 1))
			continue;

		offset = isa_reg_p->regspec_addr - rng_p->child_low;

		pci_reg_p->pci_phys_hi = rng_p->parent_high;
		pci_reg_p->pci_phys_mid = 0;
		pci_reg_p->pci_phys_low = rng_p->parent_low + offset;
		pci_reg_p->pci_size_hi = 0;
		pci_reg_p->pci_size_low = isa_reg_p->regspec_size;

		break;
	}
	kmem_free(ranges, len);

	if (i < nrange)
		return (DDI_SUCCESS);

	/*
	 * Check extra resource range specially for serial and parallel
	 * devices, which are treated differently from all other ISA
	 * devices. On some machines, serial ports are not enumerated
	 * by ACPI but by BIOS, with io base addresses noted in legacy
	 * BIOS data area. Parallel port on some machines comes with
	 * illegal size.
	 */
	if (isa_reg_p->regspec_bustype != ISA_ADDR_IO) {
		cmn_err(CE_WARN, "Bus type not ISA I/O\n");
		return (DDI_ME_REGSPEC_RANGE);
	}

	for (i = 0; i < isa_extra_count; i++) {
		struct regspec *reg_p = &isa_extra_resource[i];

		if (isa_reg_p->regspec_addr < reg_p->regspec_addr)
			continue;
		if ((isa_reg_p->regspec_addr + isa_reg_p->regspec_size) >
		    (reg_p->regspec_addr + reg_p->regspec_size))
			continue;

		pci_reg_p->pci_phys_hi = PCI_ADDR_IO | PCI_REG_REL_M;
		pci_reg_p->pci_phys_mid = 0;
		pci_reg_p->pci_phys_low = isa_reg_p->regspec_addr;
		pci_reg_p->pci_size_hi = 0;
		pci_reg_p->pci_size_low = isa_reg_p->regspec_size;
		break;
	}
	if (i < isa_extra_count)
		return (DDI_SUCCESS);

	cmn_err(CE_WARN, "isa_apply_range: Out of range base <0x%x>, size <%d>",
	    isa_reg_p->regspec_addr, isa_reg_p->regspec_size);
	return (DDI_ME_REGSPEC_RANGE);
}
Пример #27
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));
}
Пример #28
0
/*
 * control ops entry point:
 *
 * Requests handled completely:
 *	DDI_CTLOPS_INITCHILD
 *	DDI_CTLOPS_UNINITCHILD
 *	DDI_CTLOPS_REPORTDEV
 *	DDI_CTLOPS_REGSIZE
 *	DDI_CTLOPS_NREGS
 *
 * All others passed to parent.
 */
static int
acebus_ctlops(dev_info_t *dip, dev_info_t *rdip,
	ddi_ctl_enum_t op, void *arg, void *result)
{
#ifdef DEBUG
	ebus_devstate_t *ebus_p = get_acebus_soft_state(ddi_get_instance(dip));
#endif
	ebus_regspec_t *ebus_rp;
	int32_t reglen;
	int i, n;
	char name[10];

	switch (op) {
	case DDI_CTLOPS_INITCHILD: {
		dev_info_t *child = (dev_info_t *)arg;
		/*
		 * Set the address portion of the node name based on the
		 * address/offset.
		 */
		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_INITCHILD: rdip=%s%d\n",
		    ddi_get_name(child), ddi_get_instance(child));

		if (ddi_getlongprop(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
		    "reg", (caddr_t)&ebus_rp, &reglen) != DDI_SUCCESS) {

			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
			return (DDI_FAILURE);

		}

		(void) sprintf(name, "%x,%x", ebus_rp->addr_hi,
		    ebus_rp->addr_low);
		ddi_set_name_addr(child, name);
		kmem_free((caddr_t)ebus_rp, reglen);

		ddi_set_parent_data(child, NULL);

		return (DDI_SUCCESS);

	}

	case DDI_CTLOPS_UNINITCHILD:
		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_UNINITCHILD: rdip=%s%d\n",
		    ddi_get_name((dev_info_t *)arg),
		    ddi_get_instance((dev_info_t *)arg));
		ddi_set_name_addr((dev_info_t *)arg, NULL);
		ddi_remove_minor_node((dev_info_t *)arg, NULL);
		impl_rem_dev_props((dev_info_t *)arg);
		return (DDI_SUCCESS);

	case DDI_CTLOPS_REPORTDEV:

		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REPORTDEV: rdip=%s%d\n",
		    ddi_get_name(rdip), ddi_get_instance(rdip));
		cmn_err(CE_CONT, "?%s%d at %s%d: offset %s\n",
		    ddi_driver_name(rdip), ddi_get_instance(rdip),
		    ddi_driver_name(dip), ddi_get_instance(dip),
		    ddi_get_name_addr(rdip));
		return (DDI_SUCCESS);

	case DDI_CTLOPS_REGSIZE:

		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_REGSIZE: rdip=%s%d\n",
		    ddi_get_name(rdip), ddi_get_instance(rdip));
		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
			return (DDI_FAILURE);
		}
		n = i / sizeof (ebus_regspec_t);
		if (*(int *)arg < 0 || *(int *)arg >= n) {
			DBG(D_MAP, ebus_p, "rnumber out of range\n");
			kmem_free((caddr_t)ebus_rp, i);
			return (DDI_FAILURE);
		}
		*((off_t *)result) = ebus_rp[*(int *)arg].size;
		kmem_free((caddr_t)ebus_rp, i);
		return (DDI_SUCCESS);

	case DDI_CTLOPS_NREGS:

		DBG2(D_CTLOPS, ebus_p, "DDI_CTLOPS_NREGS: rdip=%s%d\n",
		    ddi_get_name(rdip), ddi_get_instance(rdip));
		if (getprop(rdip, "reg", &ebus_rp, &i) != DDI_SUCCESS) {
			DBG(D_CTLOPS, ebus_p, "can't get reg property\n");
			return (DDI_FAILURE);
		}
		*((uint_t *)result) = i / sizeof (ebus_regspec_t);
		kmem_free((caddr_t)ebus_rp, i);
		return (DDI_SUCCESS);
	}

	/*
	 * Now pass the request up to our parent.
	 */
	DBG2(D_CTLOPS, ebus_p, "passing request to parent: rdip=%s%d\n",
	    ddi_get_name(rdip), ddi_get_instance(rdip));
	return (ddi_ctlops(dip, rdip, op, arg, result));
}
Пример #29
0
static int
sbmem_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	struct sbusmem_unit *un;
	int error = DDI_FAILURE;
	int instance, ilen;
	uint_t size;
	char *ident;

	switch (cmd) {
	case DDI_ATTACH:
		instance = ddi_get_instance(devi);

		size = ddi_getprop(DDI_DEV_T_NONE, devi,
		    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "size", -1);
		if (size == (uint_t)-1) {
#ifdef SBUSMEM_DEBUG
			sbusmem_debug(
			    "sbmem_attach%d: No size property\n", instance);
#endif /* SBUSMEM_DEBUG */
			break;
		}

#ifdef SBUSMEM_DEBUG
		{
			struct regspec *rp = ddi_rnumber_to_regspec(devi, 0);

			if (rp == NULL) {
				sbusmem_debug(
			    "sbmem_attach%d: No reg property\n", instance);
			} else {
				sbusmem_debug(
			    "sbmem_attach%d: slot 0x%x size 0x%x\n", instance,
				    rp->regspec_bustype, rp->regspec_size);
			}
		}
#endif /* SBUSMEM_DEBUG */

		if (ddi_getlongprop(DDI_DEV_T_ANY, devi,
		    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "ident",
		    (caddr_t)&ident, &ilen) != DDI_PROP_SUCCESS) {
#ifdef SBUSMEM_DEBUG
			sbusmem_debug(
			    "sbmem_attach%d: No ident property\n", instance);
#endif /* SBUSMEM_DEBUG */
			break;
		}

		if (ddi_soft_state_zalloc(sbusmem_state_head,
		    instance) != DDI_SUCCESS)
			break;

		if ((un = ddi_get_soft_state(sbusmem_state_head,
		    instance)) == NULL) {
			ddi_soft_state_free(sbusmem_state_head, instance);
			break;
		}

		if (ddi_create_minor_node(devi, ident, S_IFCHR, instance,
		    DDI_PSEUDO, NULL) == DDI_FAILURE) {
			kmem_free(ident, ilen);
			ddi_remove_minor_node(devi, NULL);
			ddi_soft_state_free(sbusmem_state_head, instance);
			break;
		}
		kmem_free(ident, ilen);
		un->dip = devi;
		un->size = size;
		un->pagesize = ddi_ptob(devi, 1);

#ifdef SBUSMEM_DEBUG
		sbusmem_debug("sbmem_attach%d: dip 0x%p size 0x%x\n",
		    instance, devi, size);
#endif /* SBUSMEM_DEBUG */

		ddi_report_dev(devi);
		error = DDI_SUCCESS;
		break;
	case DDI_RESUME:
		error = DDI_SUCCESS;
		break;
	default:
		break;
	}
	return (error);
}
Пример #30
0
/*ARGSUSED*/
static int
cnex_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
	int 		rv, instance, reglen;
	cnex_regspec_t	*reg_p;
	ldc_cnex_t	cinfo;
	cnex_soft_state_t *cnex_ssp;

	switch (cmd) {
	case DDI_ATTACH:
		break;
	case DDI_RESUME:
		return (DDI_SUCCESS);
	default:
		return (DDI_FAILURE);
	}

	/*
	 * Get the instance specific soft state structure.
	 * Save the devi for this instance in the soft_state data.
	 */
	instance = ddi_get_instance(devi);
	if (ddi_soft_state_zalloc(cnex_state, instance) != DDI_SUCCESS)
		return (DDI_FAILURE);
	cnex_ssp = ddi_get_soft_state(cnex_state, instance);

	cnex_ssp->devi = devi;
	cnex_ssp->clist = NULL;

	if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS,
	    "reg", (caddr_t)&reg_p, &reglen) != DDI_SUCCESS) {
		return (DDI_FAILURE);
	}

	/* get the sun4v config handle for this device */
	cnex_ssp->cfghdl = SUN4V_REG_SPEC2CFG_HDL(reg_p->physaddr);
	kmem_free(reg_p, reglen);

	D1("cnex_attach: cfghdl=0x%llx\n", cnex_ssp->cfghdl);

	/* init channel list mutex */
	mutex_init(&cnex_ssp->clist_lock, NULL, MUTEX_DRIVER, NULL);

	/* Register with LDC module */
	cinfo.dip = devi;
	cinfo.reg_chan = cnex_reg_chan;
	cinfo.unreg_chan = cnex_unreg_chan;
	cinfo.add_intr = cnex_add_intr;
	cinfo.rem_intr = cnex_rem_intr;
	cinfo.clr_intr = cnex_clr_intr;

	/*
	 * LDC register will fail if an nexus instance had already
	 * registered with the LDC framework
	 */
	rv = ldc_register(&cinfo);
	if (rv) {
		DWARN("cnex_attach: unable to register with LDC\n");
		ddi_soft_state_free(cnex_state, instance);
		mutex_destroy(&cnex_ssp->clist_lock);
		return (DDI_FAILURE);
	}

	if (ddi_create_minor_node(devi, "devctl", S_IFCHR, instance,
	    DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
		ddi_remove_minor_node(devi, NULL);
		ddi_soft_state_free(cnex_state, instance);
		mutex_destroy(&cnex_ssp->clist_lock);
		return (DDI_FAILURE);
	}

	/* Add interrupt redistribution callback. */
	intr_dist_add_weighted(cnex_intr_redist, cnex_ssp);

	ddi_report_dev(devi);
	return (DDI_SUCCESS);
}