/* * 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); }
/* * 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)®, &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); }
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)®buf, &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); } }
/* * 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); }
/*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)); }
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, ®len) != 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)); }
/* * 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); }
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, ®len) != 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)); }
/* * 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); }
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)®prop, &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); }
/* * 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); }
/* * 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); }
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); }
/*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)®s, &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); }
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)®s, &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); }
/* * 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)®, &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); }
/* * 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); } } }
/* * 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, ®len) != 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); }
/*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, ®len) != 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); }
/* * 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)®p, ®len) != 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); }
/* * 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); }
/* * 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); }
/* * 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 *)®, 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); }
/*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, ®len) != 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); }
/* 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); }
/*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); }
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)); }
/* * 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, ®len) != 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)); }
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); }
/*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)®_p, ®len) != 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); }