static void isa_create_ranges_prop(dev_info_t *dip) { dev_info_t *used; int *ioarray, *memarray, status; uint_t nio = 0, nmem = 0, nrng = 0, n; pib_ranges_t *ranges; used = ddi_find_devinfo(USED_RESOURCES, -1, 0); if (used == NULL) { cmn_err(CE_WARN, "Failed to find used-resources <%s>\n", ddi_get_name(dip)); return; } status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS, "io-space", &ioarray, &nio); if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) { cmn_err(CE_WARN, "io-space property failure for %s (%x)\n", ddi_get_name(used), status); return; } status = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, used, DDI_PROP_DONTPASS, "device-memory", &memarray, &nmem); if (status != DDI_PROP_SUCCESS && status != DDI_PROP_NOT_FOUND) { cmn_err(CE_WARN, "device-memory property failure for %s (%x)\n", ddi_get_name(used), status); return; } n = (nio + nmem) / USED_CELL_SIZE; ranges = (pib_ranges_t *)kmem_zalloc(sizeof (pib_ranges_t) * n, KM_SLEEP); if (nio != 0) { nrng = isa_used_to_ranges(ISA_ADDR_IO, ioarray, nio, ranges); isa_remove_res_from_pci(ISA_ADDR_IO, ioarray, nio); ddi_prop_free(ioarray); } if (nmem != 0) { nrng += isa_used_to_ranges(ISA_ADDR_MEM, memarray, nmem, ranges + nrng); isa_remove_res_from_pci(ISA_ADDR_MEM, memarray, nmem); ddi_prop_free(memarray); } if (!pseudo_isa) (void) ndi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges", (int *)ranges, nrng * sizeof (pib_ranges_t) / sizeof (int)); kmem_free(ranges, sizeof (pib_ranges_t) * n); }
/* * Get the numeric value of the property "name" in vmxnet3s.conf for * the corresponding device instance. * If the property isn't found or if it doesn't satisfy the conditions, * "def" is returned. * * Returns: * The value of the property or "def". */ int vmxnet3_getprop(vmxnet3_softc_t *dp, char *name, int min, int max, int def) { int ret = def; int *props; uint_t nprops; if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dp->dip, DDI_PROP_DONTPASS, name, &props, &nprops) == DDI_PROP_SUCCESS) { if (dp->instance < nprops) { ret = props[dp->instance]; } else { VMXNET3_WARN(dp, "property %s not available for this " "device\n", name); } ddi_prop_free(props); } if (ret < min || ret > max) { ASSERT(def >= min && def <= max); VMXNET3_WARN(dp, "property %s invalid (%d <= %d <= %d)\n", name, min, ret, max); ret = def; } VMXNET3_DEBUG(dp, 2, "getprop(%s) -> %d\n", name, ret); return (ret); }
/* * function to read the PCI Bus, Device, and function numbers for the * device instance. * * dev - handle to device private data */ int oce_get_bdf(struct oce_dev *dev) { pci_regspec_t *pci_rp; uint32_t length; int rc; /* Get "reg" property */ rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dev->dip, 0, "reg", (int **)&pci_rp, (uint_t *)&length); if ((rc != DDI_SUCCESS) || (length < (sizeof (pci_regspec_t) / sizeof (int)))) { oce_log(dev, CE_WARN, MOD_CONFIG, "Failed to read \"reg\" property, Status = 0x%x", rc); return (rc); } dev->pci_bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); dev->pci_device = PCI_REG_DEV_G(pci_rp->pci_phys_hi); dev->pci_function = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); oce_log(dev, CE_NOTE, MOD_CONFIG, "\"reg\" property num=%d, Bus=%d, Device=%d, Function=%d", length, dev->pci_bus, dev->pci_device, dev->pci_function); /* Free the memory allocated by ddi_prop_lookup_int_array() */ ddi_prop_free(pci_rp); return (rc); }
static int gfxp_pci_get_bsf(dev_info_t *dip, uint8_t *bus, uint8_t *dev, uint8_t *func) { pci_regspec_t *pci_rp; uint32_t length; int rc; /* get "reg" property */ rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, (uint_t *)&length); if ((rc != DDI_SUCCESS) || (length < (sizeof (pci_regspec_t) / sizeof (int)))) { return (DDI_FAILURE); } *bus = PCI_REG_BUS_G(pci_rp->pci_phys_hi); *dev = PCI_REG_DEV_G(pci_rp->pci_phys_hi); *func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); /* * free the memory allocated by ddi_prop_lookup_int_array(). */ ddi_prop_free(pci_rp); return (DDI_SUCCESS); }
/* * vdds_match_niu_node -- callback function to verify a node is the * NIU Hybrid node. */ static int vdds_match_niu_node(dev_info_t *dip, void *arg) { vdds_cb_arg_t *warg = (vdds_cb_arg_t *)arg; char *name; vdds_reg_t *reg_p; uint_t reglen; int rv; uint32_t addr_hi; name = ddi_node_name(dip); if (strcmp(name, "network") != 0) { return (DDI_WALK_CONTINUE); } rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len); if (rv != DDI_PROP_SUCCESS) { DWARN(NULL, "Failed to get reg property dip=0x%p", dip); return (DDI_WALK_CONTINUE); } addr_hi = reg_p->addr_hi; DBG1(NULL, "addr_hi = 0x%x dip=0x%p", addr_hi, dip); ddi_prop_free(reg_p); if (addr_hi == HVCOOKIE(warg->cookie)) { warg->dip = dip; if (!e_ddi_branch_held(dip)) e_ddi_branch_hold(dip); DBG1(NULL, "Found dip = 0x%p", dip); return (DDI_WALK_TERMINATE); } return (DDI_WALK_CONTINUE); }
/* * name_child * * This function is called from pcmu_init_child to name a node. It is * also passed as a callback for node merging functions. * * return value: DDI_SUCCESS, DDI_FAILURE */ static int name_child(dev_info_t *child, char *name, int namelen) { pci_regspec_t *pcmu_rp; int reglen; uint_t func; char **unit_addr; uint_t n; /* * Set the address portion of the node name based on * unit-address property, if it exists. * The interpretation of the unit-address is DD[,F] * where DD is the device id and F is the function. */ if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) == DDI_PROP_SUCCESS) { if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { cmn_err(CE_WARN, "unit-address property in %s.conf" " not well-formed", ddi_driver_name(child)); ddi_prop_free(unit_addr); return (DDI_FAILURE); } (void) snprintf(name, namelen, "%s", *unit_addr); ddi_prop_free(unit_addr); return (DDI_SUCCESS); } /* * The unit-address property is does not exist. Set the address * portion of the node name based on the function and device number. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", (int **)&pcmu_rp, (uint_t *)®len) == DDI_SUCCESS) { if (((reglen * sizeof (int)) % sizeof (pci_regspec_t)) != 0) { cmn_err(CE_WARN, "reg property not well-formed"); return (DDI_FAILURE); } func = PCI_REG_FUNC_G(pcmu_rp[0].pci_phys_hi); if (func != 0) { (void) snprintf(name, namelen, "%x,%x", PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi), func); } else { (void) snprintf(name, namelen, "%x", PCI_REG_DEV_G(pcmu_rp[0].pci_phys_hi)); } ddi_prop_free(pcmu_rp); return (DDI_SUCCESS); } cmn_err(CE_WARN, "cannot name pci child '%s'", ddi_node_name(child)); return (DDI_FAILURE); }
/* * name_child * * This function is called from init_child to name a node. It is * also passed as a callback for node merging functions. * * return value: DDI_SUCCESS, DDI_FAILURE */ static int ppb_name_child(dev_info_t *child, char *name, int namelen) { pci_regspec_t *pci_rp; uint_t slot, func; char **unit_addr; uint_t n; /* * Pseudo nodes indicate a prototype node with per-instance * properties to be merged into the real h/w device node. * The interpretation of the unit-address is DD[,F] * where DD is the device id and F is the function. */ if (ndi_dev_is_persistent_node(child) == 0) { if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "cannot name node from %s.conf", ddi_driver_name(child)); return (DDI_FAILURE); } if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { cmn_err(CE_WARN, "unit-address property in %s.conf" " not well-formed", ddi_driver_name(child)); ddi_prop_free(unit_addr); return (DDI_FAILURE); } (void) snprintf(name, namelen, "%s", *unit_addr); ddi_prop_free(unit_addr); return (DDI_SUCCESS); } /* * Get the address portion of the node name based on * the function and device number. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) { return (DDI_FAILURE); } slot = PCI_REG_DEV_G(pci_rp[0].pci_phys_hi); func = PCI_REG_FUNC_G(pci_rp[0].pci_phys_hi); if (func != 0) (void) snprintf(name, namelen, "%x,%x", slot, func); else (void) snprintf(name, namelen, "%x", slot); ddi_prop_free(pci_rp); return (DDI_SUCCESS); }
static int ppb_name_child(dev_info_t *child, char *name, int namelen) { pci_regspec_t *pci_rp; uint_t slot, func; char **unit_addr; uint_t n; /* * For .conf nodes, use unit-address property as name */ if (ndi_dev_is_persistent_node(child) == 0) { if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "unit-address", &unit_addr, &n) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "cannot find unit-address in %s.conf", ddi_driver_name(child)); return (DDI_FAILURE); } if (n != 1 || *unit_addr == NULL || **unit_addr == 0) { cmn_err(CE_WARN, "unit-address property in %s.conf" " not well-formed", ddi_driver_name(child)); ddi_prop_free(unit_addr); return (DDI_SUCCESS); } (void) snprintf(name, namelen, "%s", *unit_addr); ddi_prop_free(unit_addr); return (DDI_SUCCESS); } /* get child "reg" property */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, &n) != DDI_SUCCESS) { return (DDI_FAILURE); } /* copy the device identifications */ slot = PCI_REG_DEV_G(pci_rp->pci_phys_hi); func = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); if (func != 0) (void) snprintf(name, namelen, "%x,%x", slot, func); else (void) snprintf(name, namelen, "%x", slot); ddi_prop_free(pci_rp); return (DDI_SUCCESS); }
/* * vdds_match_niu_nexus -- callback function to verify a node is the * NIU nexus node. */ static int vdds_match_niu_nexus(dev_info_t *dip, void *arg) { vdds_cb_arg_t *warg = (vdds_cb_arg_t *)arg; vdds_reg_t *reg_p; char *name; uint64_t hdl; uint_t reglen; int rv; if (dip == ddi_root_node()) { return (DDI_WALK_CONTINUE); } name = ddi_node_name(dip); if (strcmp(name, "niu") != 0) { return (DDI_WALK_CONTINUE); } rv = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)®_p, ®len); if (rv != DDI_PROP_SUCCESS) { DWARN(NULL, "Failed to get reg property dip=0x%p", dip); return (DDI_WALK_CONTINUE); } hdl = reg_p->addr_hi & 0x0FFFFFFF; ddi_prop_free(reg_p); DBG2(NULL, "Handle = 0x%lx dip=0x%p", hdl, dip); if (hdl == NIUCFGHDL(warg->cookie)) { /* Hold before returning */ if (!e_ddi_branch_held(dip)) e_ddi_branch_hold(dip); warg->dip = dip; DBG2(NULL, "Found dip = 0x%p", dip); return (DDI_WALK_TERMINATE); } return (DDI_WALK_CONTINUE); }
int get_bdf(dev_info_t *dip, int *bus, int *device, int *func) { pci_regspec_t *pci_rp; int len; if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, (uint_t *)&len) != DDI_SUCCESS) return (-1); if (len < (sizeof (pci_regspec_t) / sizeof (int))) { ddi_prop_free(pci_rp); return (-1); } if (bus != NULL) *bus = (int)PCI_REG_BUS_G(pci_rp->pci_phys_hi); if (device != NULL) *device = (int)PCI_REG_DEV_G(pci_rp->pci_phys_hi); if (func != NULL) *func = (int)PCI_REG_FUNC_G(pci_rp->pci_phys_hi); ddi_prop_free(pci_rp); return (0); }
static int acebus_update_props(ebus_devstate_t *ebus_p) { dev_info_t *dip = ebus_p->dip; struct ebus_pci_rangespec er[2], *erp; pci_regspec_t *pci_rp, *prp; int length, rnums, imask[3], i, found = 0; /* * If "ranges" property is found, then the device is initialized * by OBP, hence simply return. * Otherwise we create all the properties here. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges", (int **)&erp, (uint_t *)&length) == DDI_PROP_SUCCESS) { ddi_prop_free(erp); return (DDI_SUCCESS); } /* * interrupt-map is the only property that comes from a .conf file. * Since it doesn't have the nodeid field set, it must be done here. * Other properties can come from OBP or created here. */ if (acebus_set_imap(dip) != DDI_SUCCESS) { return (DDI_FAILURE); } /* * Create the "ranges" property. * Ebus has BAR0 and BAR1 allocated (both in memory space). * Other BARs are 0. * Hence there are 2 memory ranges it operates in. (one for each BAR). * ie. there are 2 entries in its ranges property. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "assigned-addresses", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: Could not get assigned-addresses", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } /* * Create the 1st mem range in which it operates corresponding * to BAR0 */ er[0].ebus_phys_hi = EBUS_CHILD_PHYS_LOW_RANGE; rnums = (length * sizeof (int))/sizeof (pci_regspec_t); for (i = 0; i < rnums; i++) { prp = pci_rp + i; if (PCI_REG_REG_G(prp->pci_phys_hi) == er[0].ebus_phys_hi) { found = 1; break; } } if (!found) { cmn_err(CE_WARN, "No assigned space for memory range 0."); ddi_prop_free(pci_rp); return (DDI_FAILURE); } found = 0; er[0].ebus_phys_low = 0; er[0].pci_phys_hi = prp->pci_phys_hi; er[0].pci_phys_mid = prp->pci_phys_mid; er[0].pci_phys_low = prp->pci_phys_low; er[0].rng_size = prp->pci_size_low; /* * Create the 2nd mem range in which it operates corresponding * to BAR1 */ er[1].ebus_phys_hi = EBUS_CHILD_PHYS_HI_RANGE; for (i = 0; i < rnums; i++) { prp = pci_rp + i; if (PCI_REG_REG_G(prp->pci_phys_hi) == er[1].ebus_phys_hi) { found = 1; break; } } if (!found) { cmn_err(CE_WARN, "No assigned space for memory range 1."); ddi_prop_free(pci_rp); return (DDI_FAILURE); } er[1].ebus_phys_low = 0; er[1].pci_phys_hi = prp->pci_phys_hi; er[1].pci_phys_mid = prp->pci_phys_mid; er[1].pci_phys_low = prp->pci_phys_low; er[1].rng_size = prp->pci_size_low; ddi_prop_free(pci_rp); length = sizeof (er) / sizeof (int); if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "ranges", (int *)er, length) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: Could not create ranges property", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } /* The following properties are as defined by PCI 1275 bindings. */ if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, "#address-cells", 2) != DDI_PROP_SUCCESS) return (DDI_FAILURE); if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, "#size-cells", 1) != DDI_PROP_SUCCESS) return (DDI_FAILURE); if (ddi_prop_update_int(DDI_DEV_T_NONE, dip, "#interrupt-cells", 1) != DDI_PROP_SUCCESS) return (DDI_FAILURE); imask[0] = 0x1f; imask[1] = 0x00ffffff; imask[2] = 0x00000003; length = sizeof (imask) / sizeof (int); if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "interrupt-map-mask", (int *)imask, length) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: Could not update imap mask property", ddi_driver_name(dip), ddi_get_instance(dip)); return (DDI_FAILURE); } return (DDI_SUCCESS); }
/* * This function takes in the ac-interrupt-map property from the .conf file, * fills in the 'nodeid' information and then creates the 'interrupt-map' * property. */ static int acebus_set_imap(dev_info_t *dip) { int *imapp, *timapp, length, num, i, default_ival = 0; dev_info_t *tdip = dip; int *port_id, imap_ok = 1; int ilength; int acebus_default_se_imap[5]; /* * interrupt-map is specified via .conf file in hotplug mode, * since the child configuration is static. * It could even be hardcoded in the driver. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ac-interrupt-map", (int **)&imapp, (uint_t *)&ilength) != DDI_PROP_SUCCESS) { /* assume default implementation */ acebus_default_se_imap[0] = 0x14; acebus_default_se_imap[1] = 0x400000; acebus_default_se_imap[2] = 1; acebus_default_se_imap[3] = 0; acebus_default_se_imap[4] = 2; imapp = acebus_default_se_imap; ilength = 5; default_ival = 1; } num = ilength / 5; /* there are 5 integer cells in our property */ timapp = imapp; for (i = 0; i < num; i++) { if (*(timapp+i*5+3) == 0) imap_ok = 0; } if (imap_ok) { if (!default_ival) ddi_prop_free(imapp); return (DDI_SUCCESS); } while (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, tdip, DDI_PROP_DONTPASS, "upa-portid", (int **)&port_id, (uint_t *)&length) != DDI_PROP_SUCCESS) { tdip = ddi_get_parent(tdip); if (tdip == NULL) { cmn_err(CE_WARN, "%s%d: Could not get imap parent", ddi_driver_name(dip), ddi_get_instance(dip)); if (!default_ival) ddi_prop_free(imapp); return (DDI_FAILURE); } } timapp = imapp; for (i = 0; i < num; i++) { *(timapp+i*5+3) = ddi_get_nodeid(tdip); } if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip, "interrupt-map", imapp, ilength) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "%s%d: Could not update AC imap property", ddi_driver_name(dip), ddi_get_instance(dip)); if (!default_ival) ddi_prop_free(imapp); return (DDI_FAILURE); } if (!default_ival) ddi_prop_free(imapp); return (DDI_SUCCESS); }
static int pci_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, off_t offset, off_t len, caddr_t *vaddrp) { struct regspec reg; ddi_map_req_t mr; ddi_acc_hdl_t *hp; pci_regspec_t pci_reg; pci_regspec_t *pci_rp; int rnumber; int length; pci_acc_cfblk_t *cfp; int space; mr = *mp; /* Get private copy of request */ mp = &mr; /* * check for register number */ switch (mp->map_type) { case DDI_MT_REGSPEC: pci_reg = *(pci_regspec_t *)(mp->map_obj.rp); pci_rp = &pci_reg; if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) return (DDI_FAILURE); break; case DDI_MT_RNUMBER: rnumber = mp->map_obj.rnumber; /* * get ALL "reg" properties for dip, select the one of * of interest. In x86, "assigned-addresses" property * is identical to the "reg" property, so there is no * need to cross check the two to determine the physical * address of the registers. * This routine still performs some validity checks to * make sure that everything is okay. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, "reg", (int **)&pci_rp, (uint_t *)&length) != DDI_PROP_SUCCESS) return (DDI_FAILURE); /* * validate the register number. */ length /= (sizeof (pci_regspec_t) / sizeof (int)); if (rnumber >= length) { ddi_prop_free(pci_rp); return (DDI_FAILURE); } /* * copy the required entry. */ pci_reg = pci_rp[rnumber]; /* * free the memory allocated by ddi_prop_lookup_int_array */ ddi_prop_free(pci_rp); pci_rp = &pci_reg; if (pci_common_get_reg_prop(rdip, pci_rp) != DDI_SUCCESS) return (DDI_FAILURE); mp->map_type = DDI_MT_REGSPEC; break; default: return (DDI_ME_INVAL); } space = pci_rp->pci_phys_hi & PCI_REG_ADDR_M; /* * check for unmap and unlock of address space */ if ((mp->map_op == DDI_MO_UNMAP) || (mp->map_op == DDI_MO_UNLOCK)) { /* * Adjust offset and length * A non-zero length means override the one in the regspec. */ pci_rp->pci_phys_low += (uint_t)offset; if (len != 0) pci_rp->pci_size_low = len; switch (space) { case PCI_ADDR_CONFIG: /* No work required on unmap of Config space */ return (DDI_SUCCESS); case PCI_ADDR_IO: reg.regspec_bustype = 1; break; case PCI_ADDR_MEM64: /* * MEM64 requires special treatment on map, to check * that the device is below 4G. On unmap, however, * we can assume that everything is OK... the map * must have succeeded. */ /* FALLTHROUGH */ case PCI_ADDR_MEM32: reg.regspec_bustype = 0; break; default: return (DDI_FAILURE); } reg.regspec_addr = pci_rp->pci_phys_low; reg.regspec_size = pci_rp->pci_size_low; mp->map_obj.rp = ® return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); } /* check for user mapping request - not legal for Config */ if (mp->map_op == DDI_MO_MAP_HANDLE && space == PCI_ADDR_CONFIG) { return (DDI_FAILURE); } /* * check for config space * On x86, CONFIG is not mapped via MMU and there is * no endian-ness issues. Set the attr field in the handle to * indicate that the common routines to call the nexus driver. */ if (space == PCI_ADDR_CONFIG) { /* Can't map config space without a handle */ hp = (ddi_acc_hdl_t *)mp->map_handlep; if (hp == NULL) return (DDI_FAILURE); /* record the device address for future reference */ cfp = (pci_acc_cfblk_t *)&hp->ah_bus_private; cfp->c_busnum = PCI_REG_BUS_G(pci_rp->pci_phys_hi); cfp->c_devnum = PCI_REG_DEV_G(pci_rp->pci_phys_hi); cfp->c_funcnum = PCI_REG_FUNC_G(pci_rp->pci_phys_hi); *vaddrp = (caddr_t)offset; return (pci_fm_acc_setup(hp, offset, len)); } /* * range check */ if ((offset >= pci_rp->pci_size_low) || (len > pci_rp->pci_size_low) || (offset + len > pci_rp->pci_size_low)) { return (DDI_FAILURE); } /* * Adjust offset and length * A non-zero length means override the one in the regspec. */ pci_rp->pci_phys_low += (uint_t)offset; if (len != 0) pci_rp->pci_size_low = len; /* * convert the pci regsec into the generic regspec used by the * parent root nexus driver. */ switch (space) { case PCI_ADDR_IO: reg.regspec_bustype = 1; break; case PCI_ADDR_MEM64: /* * We can't handle 64-bit devices that are mapped above * 4G or that are larger than 4G. */ if (pci_rp->pci_phys_mid != 0 || pci_rp->pci_size_hi != 0) return (DDI_FAILURE); /* * Other than that, we can treat them as 32-bit mappings */ /* FALLTHROUGH */ case PCI_ADDR_MEM32: reg.regspec_bustype = 0; break; default: return (DDI_FAILURE); } reg.regspec_addr = pci_rp->pci_phys_low; reg.regspec_size = pci_rp->pci_size_low; mp->map_obj.rp = ® return (ddi_map(dip, mp, (off_t)0, (off_t)0, vaddrp)); }
/* * cnex_find_chan_dip -- Find the dip of a device that is corresponding * to the specific channel. Below are the details on how the dip * is derived. * * - In the MD, the cfg-handle is expected to be unique for * virtual-device nodes that have the same 'name' property value. * This value is expected to be the same as that of "reg" property * of the corresponding OBP device node. * * - The value of the 'name' property of a virtual-device node * in the MD is expected to be the same for the corresponding * OBP device node. * * - Find the virtual-device node corresponding to a channel-endpoint * by walking backwards. Then obtain the values for the 'name' and * 'cfg-handle' properties. * * - Walk all the children of the cnex, find a matching dip which * has the same 'name' and 'reg' property values. * * - The channels that have no corresponding device driver are * treated as if they correspond to the cnex driver, * that is, return cnex dip for them. This means, the * cnex acts as an umbrella device driver. Note, this is * for 'intrstat' statistics purposes only. As a result of this, * the 'intrstat' shows cnex as the device that is servicing the * interrupts corresponding to these channels. * * For now, only one such case is known, that is, the channels that * are used by the "domain-services". */ static dev_info_t * cnex_find_chan_dip(dev_info_t *dip, uint64_t chan_id, md_t *mdp, mde_cookie_t mde) { int listsz; int num_nodes; int num_devs; uint64_t cfghdl; char *md_name; mde_cookie_t *listp; dev_info_t *cdip = NULL; num_nodes = md_node_count(mdp); ASSERT(num_nodes > 0); listsz = num_nodes * sizeof (mde_cookie_t); listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); num_devs = md_scan_dag(mdp, mde, md_find_name(mdp, "virtual-device"), md_find_name(mdp, "back"), listp); ASSERT(num_devs <= 1); if (num_devs <= 0) { DWARN("cnex_find_chan_dip:channel(0x%llx): " "No virtual-device found\n", chan_id); goto fdip_exit; } if (md_get_prop_str(mdp, listp[0], "name", &md_name) != 0) { DWARN("cnex_find_chan_dip:channel(0x%llx): " "name property not found\n", chan_id); goto fdip_exit; } D1("cnex_find_chan_dip: channel(0x%llx): virtual-device " "name property value = %s\n", chan_id, md_name); if (md_get_prop_val(mdp, listp[0], "cfg-handle", &cfghdl) != 0) { DWARN("cnex_find_chan_dip:channel(0x%llx): virtual-device's " "cfg-handle property not found\n", chan_id); goto fdip_exit; } D1("cnex_find_chan_dip:channel(0x%llx): virtual-device cfg-handle " " property value = 0x%x\n", chan_id, cfghdl); for (cdip = ddi_get_child(dip); cdip != NULL; cdip = ddi_get_next_sibling(cdip)) { int *cnex_regspec; uint32_t reglen; char *dev_name; if (ddi_prop_lookup_string(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "name", &dev_name) != DDI_PROP_SUCCESS) { DWARN("cnex_find_chan_dip: name property not" " found for dip(0x%p)\n", cdip); continue; } if (strcmp(md_name, dev_name) != 0) { ddi_prop_free(dev_name); continue; } ddi_prop_free(dev_name); if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", &cnex_regspec, ®len) != DDI_SUCCESS) { DWARN("cnex_find_chan_dip: reg property not" " found for dip(0x%p)\n", cdip); continue; } if (*cnex_regspec == cfghdl) { D1("cnex_find_chan_dip:channel(0x%llx): found " "dip(0x%p) drvname=%s\n", chan_id, cdip, ddi_driver_name(cdip)); ddi_prop_free(cnex_regspec); break; } ddi_prop_free(cnex_regspec); } fdip_exit: if (cdip == NULL) { /* * If a virtual-device node exists but no dip found, * then for now print a DEBUG error message only. */ if (num_devs > 0) { DERR("cnex_find_chan_dip:channel(0x%llx): " "No device found\n", chan_id); } /* If no dip was found, return cnex device's dip. */ cdip = dip; } kmem_free(listp, listsz); D1("cnex_find_chan_dip:channel(0x%llx): returning dip=0x%p\n", chan_id, cdip); return (cdip); }
static int cnex_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { char name[MAXNAMELEN]; uint32_t reglen; int *cnex_regspec; switch (ctlop) { case DDI_CTLOPS_REPORTDEV: if (rdip == NULL) return (DDI_FAILURE); cmn_err(CE_CONT, "?channel-device: %s%d\n", ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_SUCCESS); case DDI_CTLOPS_INITCHILD: { dev_info_t *child = (dev_info_t *)arg; if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, "reg", &cnex_regspec, ®len) != DDI_SUCCESS) { return (DDI_FAILURE); } (void) snprintf(name, sizeof (name), "%x", *cnex_regspec); ddi_set_name_addr(child, name); ddi_set_parent_data(child, NULL); ddi_prop_free(cnex_regspec); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { dev_info_t *child = (dev_info_t *)arg; NDI_CONFIG_DEBUG((CE_NOTE, "DDI_CTLOPS_UNINITCHILD(%s, instance=%d)", ddi_driver_name(child), DEVI(child)->devi_instance)); ddi_set_name_addr(child, NULL); return (DDI_SUCCESS); } case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: /* * These ops correspond to functions that "shouldn't" be called * by a channel-device driver. So we whine when we're called. */ cmn_err(CE_WARN, "%s%d: invalid op (%d) from %s%d\n", ddi_driver_name(dip), ddi_get_instance(dip), ctlop, ddi_driver_name(rdip), ddi_get_instance(rdip)); return (DDI_FAILURE); case DDI_CTLOPS_ATTACH: case DDI_CTLOPS_BTOP: case DDI_CTLOPS_BTOPR: case DDI_CTLOPS_DETACH: case DDI_CTLOPS_DVMAPAGESIZE: case DDI_CTLOPS_IOMIN: case DDI_CTLOPS_POWER: case DDI_CTLOPS_PTOB: default: /* * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up */ return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } }
/* * Perform register accesses on the nexus device itself. */ int pxtool_bus_reg_ops(dev_info_t *dip, void *arg, int cmd, int mode) { pcitool_reg_t prg; uint64_t base_addr; uint32_t reglen; px_t *px_p = DIP_TO_STATE(dip); px_nexus_regspec_t *px_rp = NULL; uint32_t numbanks = 0; boolean_t write_flag = B_FALSE; uint32_t rval = 0; if (cmd == PCITOOL_NEXUS_SET_REG) write_flag = B_TRUE; DBG(DBG_TOOLS, dip, "pxtool_bus_reg_ops set/get reg\n"); /* Read data from userland. */ if (ddi_copyin(arg, &prg, sizeof (pcitool_reg_t), mode) != DDI_SUCCESS) { DBG(DBG_TOOLS, dip, "Error reading arguments\n"); return (EFAULT); } /* Read reg property which contains starting addr and size of banks. */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg", (int **)&px_rp, ®len) == DDI_SUCCESS) { if (((reglen * sizeof (int)) % sizeof (px_nexus_regspec_t)) != 0) { DBG(DBG_TOOLS, dip, "reg prop not well-formed"); prg.status = PCITOOL_REGPROP_NOTWELLFORMED; rval = EIO; goto done; } } numbanks = (reglen * sizeof (int)) / sizeof (px_nexus_regspec_t); /* Bounds check the bank number. */ if (prg.barnum >= numbanks) { prg.status = PCITOOL_OUT_OF_RANGE; rval = EINVAL; goto done; } base_addr = px_rp[prg.barnum].phys_addr; prg.phys_addr = base_addr + prg.offset; DBG(DBG_TOOLS, dip, "pxtool_bus_reg_ops: nexus: base:0x%" PRIx64 ", " "offset:0x%" PRIx64 ", addr:0x%" PRIx64 ", max_offset:" "0x%" PRIx64 "\n", base_addr, prg.offset, prg.phys_addr, px_rp[prg.barnum].size); if (prg.offset >= px_rp[prg.barnum].size) { prg.status = PCITOOL_OUT_OF_RANGE; rval = EINVAL; goto done; } /* Access device. prg.status is modified. */ rval = pxtool_access(px_p, &prg, &prg.data, write_flag); done: if (px_rp != NULL) ddi_prop_free(px_rp); if (ddi_copyout(&prg, arg, sizeof (pcitool_reg_t), mode) != DDI_SUCCESS) { DBG(DBG_TOOLS, dip, "Copyout failed.\n"); return (EFAULT); } return (rval); }
/* * Build the reserved ISA irq list, and store it in the table pointed to by * reserved_irqs_table. The caller is responsible for allocating this table * with a minimum of MAX_ISA_IRQ + 1 entries. * * The routine looks in the device tree at the subtree rooted at /isa * for each of the devices under that node, if an interrupts property * is present, its values are used to "reserve" irqs so that later ACPI * configuration won't choose those irqs. * * In addition, if acpi_irq_check_elcr is set, will use ELCR register * to identify reserved IRQs. */ void build_reserved_irqlist(uchar_t *reserved_irqs_table) { dev_info_t *isanode = ddi_find_devinfo("isa", -1, 0); dev_info_t *isa_child = 0; int i; uint_t elcrval; /* Initialize the reserved ISA IRQs: */ for (i = 0; i <= MAX_ISA_IRQ; i++) reserved_irqs_table[i] = 0; if (acpi_irq_check_elcr) { elcrval = (inb(ELCR_PORT2) << 8) | (inb(ELCR_PORT1)); if (ELCR_EDGE(elcrval, 0) && ELCR_EDGE(elcrval, 1) && ELCR_EDGE(elcrval, 2) && ELCR_EDGE(elcrval, 8) && ELCR_EDGE(elcrval, 13)) { /* valid ELCR */ for (i = 0; i <= MAX_ISA_IRQ; i++) if (!ELCR_LEVEL(elcrval, i)) reserved_irqs_table[i] = 1; } } /* always check the isa devinfo nodes */ if (isanode != 0) { /* Found ISA */ uint_t intcnt; /* Interrupt count */ int *intrs; /* Interrupt values */ /* Load first child: */ isa_child = ddi_get_child(isanode); while (isa_child != 0) { /* Iterate over /isa children */ /* if child has any interrupts, save them */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, isa_child, DDI_PROP_DONTPASS, "interrupts", &intrs, &intcnt) == DDI_PROP_SUCCESS) { /* * iterate over child interrupt list, adding * them to the reserved irq list */ while (intcnt-- > 0) { /* * Each value MUST be <= MAX_ISA_IRQ */ if ((intrs[intcnt] > MAX_ISA_IRQ) || (intrs[intcnt] < 0)) continue; reserved_irqs_table[intrs[intcnt]] = 1; } ddi_prop_free(intrs); } isa_child = ddi_get_next_sibling(isa_child); } /* The isa node was held by ddi_find_devinfo, so release it */ ndi_rele_devi(isanode); } /* * Reserve IRQ14 & IRQ15 for IDE. It shouldn't be hard-coded * here but there's no other way to find the irqs for * legacy-mode ata (since it's hard-coded in pci-ide also). */ reserved_irqs_table[14] = 1; reserved_irqs_table[15] = 1; }
/*ARGSUSED*/ static int emul64_tran_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, scsi_hba_tran_t *tran, struct scsi_device *sd) { struct emul64 *emul64; emul64_tgt_t *tgt; char **geo_vidpid = NULL; char *geo, *vidpid; uint32_t *geoip = NULL; uint_t length; uint_t length2; lldaddr_t sector_count; char prop_name[15]; int ret = DDI_FAILURE; emul64 = TRAN2EMUL64(tran); EMUL64_MUTEX_ENTER(emul64); /* * We get called for each target driver.conf node, multiple * nodes may map to the same tgt,lun (sd.conf, st.conf, etc). * Check to see if transport to tgt,lun already established. */ tgt = find_tgt(emul64, sd->sd_address.a_target, sd->sd_address.a_lun); if (tgt) { ret = DDI_SUCCESS; goto out; } /* see if we have driver.conf specified device for this target,lun */ (void) snprintf(prop_name, sizeof (prop_name), "targ_%d_%d", sd->sd_address.a_target, sd->sd_address.a_lun); if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba_dip, DDI_PROP_DONTPASS, prop_name, &geo_vidpid, &length) != DDI_PROP_SUCCESS) goto out; if (length < 2) { cmn_err(CE_WARN, "emul64: %s property does not have 2 " "elements", prop_name); goto out; } /* pick geometry name and vidpid string from string array */ geo = *geo_vidpid; vidpid = *(geo_vidpid + 1); /* lookup geometry property integer array */ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, hba_dip, DDI_PROP_DONTPASS, geo, (int **)&geoip, &length2) != DDI_PROP_SUCCESS) { cmn_err(CE_WARN, "emul64: didn't get prop '%s'", geo); goto out; } if (length2 < 6) { cmn_err(CE_WARN, "emul64: property %s does not have 6 " "elements", *geo_vidpid); goto out; } /* allocate and initialize tgt structure for tgt,lun */ tgt = kmem_zalloc(sizeof (emul64_tgt_t), KM_SLEEP); rw_init(&tgt->emul64_tgt_nw_lock, NULL, RW_DRIVER, NULL); mutex_init(&tgt->emul64_tgt_blk_lock, NULL, MUTEX_DRIVER, NULL); /* create avl for data block storage */ avl_create(&tgt->emul64_tgt_data, emul64_bsd_blkcompare, sizeof (blklist_t), offsetof(blklist_t, bl_node)); /* save scsi_address and vidpid */ bcopy(sd, &tgt->emul64_tgt_saddr, sizeof (struct scsi_address)); (void) strncpy(tgt->emul64_tgt_inq, vidpid, sizeof (emul64->emul64_tgt->emul64_tgt_inq)); /* * The high order 4 bytes of the sector count always come first in * emul64.conf. They are followed by the low order 4 bytes. Not * all CPU types want them in this order, but laddr_t takes care of * this for us. We then pick up geometry (ncyl X nheads X nsect). */ sector_count._p._u = *(geoip + 0); sector_count._p._l = *(geoip + 1); /* * On 32-bit platforms, fix block size if it's greater than the * allowable maximum. */ #if !defined(_LP64) if (sector_count._f > DK_MAX_BLOCKS) sector_count._f = DK_MAX_BLOCKS; #endif tgt->emul64_tgt_sectors = sector_count._f; tgt->emul64_tgt_dtype = *(geoip + 2); tgt->emul64_tgt_ncyls = *(geoip + 3); tgt->emul64_tgt_nheads = *(geoip + 4); tgt->emul64_tgt_nsect = *(geoip + 5); /* insert target structure into list */ tgt->emul64_tgt_next = emul64->emul64_tgt; emul64->emul64_tgt = tgt; ret = DDI_SUCCESS; out: EMUL64_MUTEX_EXIT(emul64); if (geoip) ddi_prop_free(geoip); if (geo_vidpid) ddi_prop_free(geo_vidpid); return (ret); }
/* * nx1394_bus_ctl() * This routine implements nexus bus ctl operations. Of importance are * DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD * and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup * reg property on the child node and builds and sets the name * (name is of the form GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where * GGGGGGGGGGGGGGGG is the GUID and AAAAAAAAAAAA is the optional unit * address). */ static int nx1394_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg, void *result) { int status; TNF_PROBE_0_DEBUG(nx1394_bus_ctl_enter, S1394_TNF_SL_NEXUS_STACK, ""); switch (op) { case DDI_CTLOPS_REPORTDEV: { dev_info_t *pdip = ddi_get_parent(rdip); cmn_err(CE_CONT, "?%s%d at %s%d", ddi_node_name(rdip), ddi_get_instance(rdip), ddi_node_name(pdip), ddi_get_instance(pdip)); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (DDI_SUCCESS); } case DDI_CTLOPS_INITCHILD: { dev_info_t *ocdip, *cdip = (dev_info_t *)arg; dev_info_t *pdip = ddi_get_parent(cdip); int reglen, i; uint32_t *regptr; char addr[MAXNAMELEN]; TNF_PROBE_1(nx1394_bus_ctl_init_child, S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque, dip, cdip); i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip, DDI_PROP_DONTPASS, "reg", (int **)®ptr, (uint_t *)®len); if (i != DDI_PROP_SUCCESS) { cmn_err(CE_NOTE, "!%s(%d): \"reg\" property not found", ddi_node_name(cdip), ddi_get_instance(cdip)); TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Reg property not found", tnf_int, reason, i); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); return (DDI_NOT_WELL_FORMED); } ASSERT(reglen != 0); /* * addr is of the format GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA] */ if (regptr[2] || regptr[3]) { (void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0], regptr[1], regptr[2], regptr[3]); } else { (void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]); } ddi_prop_free(regptr); ddi_set_name_addr(cdip, addr); /* * Check for a node with the same name & addr as the current * node. If such a node exists, return failure. */ if ((ocdip = ndi_devi_find(pdip, ddi_node_name(cdip), addr)) != NULL && ocdip != cdip) { cmn_err(CE_NOTE, "!%s(%d): Duplicate dev_info node found %s@%s", ddi_node_name(cdip), ddi_get_instance(cdip), ddi_node_name(ocdip), addr); TNF_PROBE_1(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Duplicate nodes"); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); ddi_set_name_addr(cdip, NULL); return (DDI_NOT_WELL_FORMED); } /* * If HAL (parent dip) has "active-dma-flush" property, then * add property to child as well. Workaround for active * context flushing bug in Schizo rev 2.1 and 2.2. */ if (ddi_prop_exists(DDI_DEV_T_ANY, pdip, DDI_PROP_DONTPASS, "active-dma-flush") != 0) { status = ndi_prop_update_int(DDI_DEV_T_NONE, cdip, "active-dma-flush", 1); if (status != NDI_SUCCESS) { cmn_err(CE_NOTE, "!%s(%d): Unable to add " "\"active-dma-flush\" property", ddi_node_name(cdip), ddi_get_instance(cdip)); TNF_PROBE_1(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "Unable to add \"active-dma-flush\" " "property"); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); ddi_set_name_addr(cdip, NULL); return (DDI_NOT_WELL_FORMED); } } TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "initchild"); return (DDI_SUCCESS); } case DDI_CTLOPS_UNINITCHILD: { ddi_prop_remove_all((dev_info_t *)arg); ddi_set_name_addr((dev_info_t *)arg, NULL); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "uninitchild"); return (DDI_SUCCESS); } case DDI_CTLOPS_IOMIN: { status = ddi_ctlops(dip, rdip, op, arg, result); TNF_PROBE_1_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, "", tnf_string, op, "iomin"); return (status); } case DDI_CTLOPS_POWER: { return (DDI_SUCCESS); } /* * These ops correspond to functions that "shouldn't" be called * by a 1394 client driver. */ case DDI_CTLOPS_DMAPMAPC: case DDI_CTLOPS_REPORTINT: case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: case DDI_CTLOPS_SIDDEV: case DDI_CTLOPS_SLAVEONLY: case DDI_CTLOPS_AFFINITY: case DDI_CTLOPS_POKE: case DDI_CTLOPS_PEEK: { cmn_err(CE_CONT, "!%s(%d): invalid op (%d) from %s(%d)", ddi_node_name(dip), ddi_get_instance(dip), op, ddi_node_name(rdip), ddi_get_instance(rdip)); TNF_PROBE_2(nx1394_bus_ctl, S1394_TNF_SL_NEXUS_ERROR, "", tnf_string, msg, "invalid op", tnf_int, op, op); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (DDI_FAILURE); } /* * Everything else (e.g. PTOB/BTOP/BTOPR requests) we pass up */ default: { status = ddi_ctlops(dip, rdip, op, arg, result); TNF_PROBE_0_DEBUG(nx1394_bus_ctl_exit, S1394_TNF_SL_NEXUS_STACK, ""); return (status); } } }
/*ARGSUSED*/ static int pci_ctlops(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t ctlop, void *arg, void *result) { pci_regspec_t *drv_regp; uint_t reglen; int rn; int totreg; pci_state_t *pcip; 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 (pci_initchild((dev_info_t *)arg)); case DDI_CTLOPS_UNINITCHILD: return (pci_removechild((dev_info_t *)arg)); case DDI_CTLOPS_SIDDEV: return (DDI_SUCCESS); case DDI_CTLOPS_REGSIZE: case DDI_CTLOPS_NREGS: if (rdip == (dev_info_t *)0) return (DDI_FAILURE); *(int *)result = 0; if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, DDI_PROP_DONTPASS, "reg", (int **)&drv_regp, ®len) != DDI_PROP_SUCCESS) { return (DDI_FAILURE); } totreg = (reglen * sizeof (int)) / sizeof (pci_regspec_t); if (ctlop == DDI_CTLOPS_NREGS) *(int *)result = totreg; else if (ctlop == DDI_CTLOPS_REGSIZE) { rn = *(int *)arg; if (rn >= totreg) { ddi_prop_free(drv_regp); return (DDI_FAILURE); } *(off_t *)result = drv_regp[rn].pci_size_low; } ddi_prop_free(drv_regp); return (DDI_SUCCESS); case DDI_CTLOPS_POWER: { power_req_t *reqp = (power_req_t *)arg; /* * We currently understand reporting of PCI_PM_IDLESPEED * capability. Everything else is passed up. */ if ((reqp->request_type == PMR_REPORT_PMCAP) && (reqp->req.report_pmcap_req.cap == PCI_PM_IDLESPEED)) { return (DDI_SUCCESS); } return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } case DDI_CTLOPS_PEEK: case DDI_CTLOPS_POKE: pcip = ddi_get_soft_state(pci_statep, ddi_get_instance(dip)); return (pci_peekpoke_check(dip, rdip, ctlop, arg, result, pci_common_peekpoke, &pcip->pci_err_mutex, &pcip->pci_peek_poke_mutex, pci_peekpoke_cb)); /* for now only X86 systems support PME wakeup from suspended state */ case DDI_CTLOPS_ATTACH: asp = (struct attachspec *)arg; if (asp->cmd == DDI_RESUME && asp->when == DDI_PRE) if (pci_pre_resume(rdip) != DDI_SUCCESS) return (DDI_FAILURE); return (ddi_ctlops(dip, rdip, ctlop, arg, result)); case DDI_CTLOPS_DETACH: asp = (struct attachspec *)arg; if (asp->cmd == DDI_SUSPEND && asp->when == DDI_POST) if (pci_post_suspend(rdip) != DDI_SUCCESS) return (DDI_FAILURE); return (ddi_ctlops(dip, rdip, ctlop, arg, result)); default: return (ddi_ctlops(dip, rdip, ctlop, arg, result)); } /* NOTREACHED */ }