static int vnex_attach(device_t dev) { struct vnex_devinfo *vndi; struct vnex_softc *sc; device_t cdev; phandle_t node; mde_cookie_t rootnode, *listp = NULL; int i, listsz, num_nodes, num_devices; md_t *mdp; node = ofw_bus_get_node(dev); if (node == -1) panic("%s: ofw_bus_get_node failed.", __func__); sc = device_get_softc(dev); sc->sc_intr_rman.rm_type = RMAN_ARRAY; sc->sc_intr_rman.rm_descr = "Interrupts"; sc->sc_mem_rman.rm_type = RMAN_ARRAY; sc->sc_mem_rman.rm_descr = "Device Memory"; if (rman_init(&sc->sc_intr_rman) != 0 || rman_init(&sc->sc_mem_rman) != 0 || rman_manage_region(&sc->sc_intr_rman, 0, IV_MAX - 1) != 0 || rman_manage_region(&sc->sc_mem_rman, 0ULL, ~0ULL) != 0) panic("%s: failed to set up rmans.", __func__); if ((mdp = md_get()) == NULL) return (ENXIO); num_nodes = md_node_count(mdp); listsz = num_nodes * sizeof(mde_cookie_t); listp = (mde_cookie_t *)malloc(listsz, M_DEVBUF, M_WAITOK); rootnode = md_root_node(mdp); /* * scan the machine description for virtual devices */ num_devices = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"), md_find_name(mdp, "fwd"), listp); for (i = 0; i < num_devices; i++) { if ((vndi = vnex_setup_dinfo(dev, listp[i])) == NULL) continue; cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", vndi->vndi_mbdinfo.mbd_name); vnex_destroy_dinfo(vndi); continue; } device_set_ivars(cdev, vndi); } bus_generic_attach(dev); free(listp, M_DEVBUF); return (0); }
/* * Failed to allocate the list : Return value -1 * md_scan_dag API failed : Return the result from md_scan_dag API */ int md_alloc_scan_dag(md_t *ptr, mde_cookie_t startnode, char *node_name, char *dag, mde_cookie_t **list) { int res; md_impl_t *mdp = (md_impl_t *)ptr; *list = (mde_cookie_t *)mdp->allocp(sizeof (mde_cookie_t) * mdp->node_count); if (*list == NULL) return (-1); res = md_scan_dag(ptr, startnode, md_find_name(ptr, node_name), md_find_name(ptr, dag), *list); /* * If md_scan_dag API returned 0 or -1 then free the buffer * and return -1 to indicate the error from this API. */ if (res < 1) { md_free_scan_dag(ptr, list); *list = NULL; } return (res); }
/* * Extract from the PRI the processor, strand and their fru identity */ int cpu_mdesc_init(topo_mod_t *mod, md_info_t *chip) { int rc = -1; md_t *mdp; ssize_t bufsiz = 0; uint64_t *bufp; ldom_hdl_t *lhp; uint32_t type = 0; /* get the PRI/MD */ if ((lhp = ldom_init(cpu_alloc, cpu_free)) == NULL) { topo_mod_dprintf(mod, "ldom_init() failed\n"); return (topo_mod_seterrno(mod, EMOD_NOMEM)); } (void) ldom_get_type(lhp, &type); if ((type & LDOM_TYPE_CONTROL) != 0) { bufsiz = ldom_get_core_md(lhp, &bufp); } else { bufsiz = ldom_get_local_md(lhp, &bufp); } if (bufsiz <= 0) { topo_mod_dprintf(mod, "failed to get the PRI/MD\n"); ldom_fini(lhp); return (-1); } if ((mdp = md_init_intern(bufp, cpu_alloc, cpu_free)) == NULL || md_node_count(mdp) <= 0) { cpu_free(bufp, (size_t)bufsiz); ldom_fini(lhp); return (-1); } /* * N1 MD contains cpu nodes while N2 MD contains component nodes. */ if (md_find_name(mdp, MD_STR_COMPONENT) != MDE_INVAL_STR_COOKIE) { rc = cpu_n2_mdesc_init(mod, mdp, chip); } else if (md_find_name(mdp, MD_STR_CPU) != MDE_INVAL_STR_COOKIE) { rc = cpu_n1_mdesc_init(mod, mdp, chip); } else { topo_mod_dprintf(mod, "Unsupported PRI/MD\n"); rc = -1; } cpu_free(bufp, (size_t)bufsiz); (void) md_fini(mdp); ldom_fini(lhp); return (rc); }
int md_get_prop_str(md_t *ptr, mde_cookie_t node, char *namep, char **strp) { mde_str_cookie_t prop_name; md_impl_t *mdp; mde_cookie_t elem; mdp = (md_impl_t *)ptr; if (node == MDE_INVAL_ELEM_COOKIE) { return (-1); } prop_name = md_find_name(ptr, namep); if (prop_name == MDE_INVAL_STR_COOKIE) { return (-1); } elem = md_find_node_prop(mdp, node, prop_name, MDET_PROP_STR); if (elem != MDE_INVAL_ELEM_COOKIE) { md_element_t *mdep; mdep = &(mdp->mdep[(int)elem]); *strp = (char *)(mdp->datap+ MDE_PROP_DATA_OFFSET(mdep)); return (0); } return (-1); /* no such property name */ }
int md_get_prop_val(md_t *ptr, mde_cookie_t node, char *namep, uint64_t *valp) { mde_str_cookie_t prop_name; md_impl_t *mdp; mde_cookie_t elem; mdp = (md_impl_t *)ptr; if (node == MDE_INVAL_ELEM_COOKIE) { return (-1); } prop_name = md_find_name(ptr, namep); if (prop_name == MDE_INVAL_STR_COOKIE) { return (-1); } elem = md_find_node_prop(mdp, node, prop_name, MDET_PROP_VAL); if (elem != MDE_INVAL_ELEM_COOKIE) { md_element_t *mdep; mdep = &(mdp->mdep[(int)elem]); *valp = MDE_PROP_VALUE(mdep); return (0); } return (-1); /* no such property name */ }
int md_vdev_find_node(device_t dev, mde_cookie_t *valp) { uint64_t cfg_handle; mde_cookie_t rootnode, node, *listp = NULL; int i, listsz, num_nodes, num_devices, error; md_t *mdp; cfg_handle = mdesc_bus_get_handle(dev); error = EINVAL; if ((mdp = md_get()) == NULL) return (ENXIO); num_nodes = md_node_count(mdp); listsz = num_nodes * sizeof(mde_cookie_t); listp = (mde_cookie_t *)malloc(listsz, M_DEVBUF, M_WAITOK); rootnode = md_root_node(mdp); node = error = 0; num_devices = md_scan_dag(mdp, rootnode, md_find_name(mdp, "virtual-device"), md_find_name(mdp, "fwd"), listp); if (num_devices == 0) { error = ENOENT; goto done; } for (i = 0; i < num_devices; i++) { uint64_t thandle; node = listp[i]; md_get_prop_val(mdp, node, "cfg-handle", &thandle); if (thandle == cfg_handle) { *valp = node; break; } } done: md_put(mdp); return (error); }
static int i_vldc_get_port_channel(md_t *mdp, mde_cookie_t node, uint64_t *ldc_id) { int num_nodes, nchan; size_t listsz; mde_cookie_t *listp; /* * Find the channel-endpoint node(s) (which should be under this * port node) which contain the channel id(s). */ if ((num_nodes = md_node_count(mdp)) <= 0) { cmn_err(CE_NOTE, "?i_vldc_get_port_channel: invalid number of " "channel-endpoint nodes found (%d)", num_nodes); return (-1); } /* allocate space for node list */ listsz = num_nodes * sizeof (mde_cookie_t); listp = kmem_alloc(listsz, KM_SLEEP); nchan = md_scan_dag(mdp, node, md_find_name(mdp, "channel-endpoint"), md_find_name(mdp, "fwd"), listp); if (nchan <= 0) { cmn_err(CE_NOTE, "?i_vldc_get_port_channel: no channel-endpoint" " nodes found"); kmem_free(listp, listsz); return (-1); } D2("i_vldc_get_port_channel: %d channel-endpoint nodes found", nchan); /* use property from first node found */ if (md_get_prop_val(mdp, listp[0], "id", ldc_id)) { cmn_err(CE_NOTE, "?i_vldc_get_port_channel: channel-endpoint " "has no 'id' property"); kmem_free(listp, listsz); return (-1); } kmem_free(listp, listsz); return (0); }
static void init_domaining_capabilities(md_t *mdp, mde_cookie_t *listp) { mde_cookie_t rootnode; int num_nodes; uint64_t val = 0; rootnode = md_root_node(mdp); ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "platform"), md_find_name(mdp, "fwd"), listp); /* should only be one platform node */ ASSERT(num_nodes == 1); if (md_get_prop_val(mdp, *listp, "domaining-enabled", &val) != 0) { /* * The property is not present. This implies * that the firmware does not support domaining * features. */ MDP(("'domaining-enabled' property not present\n")); domaining_capabilities = 0; return; } domaining_capabilities = DOMAINING_SUPPORTED; if (val == 1) { if (force_domaining_disabled) { MDP(("domaining manually disabled\n")); } else { domaining_capabilities |= DOMAINING_ENABLED; } } MDP(("domaining_capabilities= 0x%x\n", domaining_capabilities)); }
static mde_cookie_t mdeg_find_start_node(md_t *md, mdeg_node_spec_t *nspec) { mde_cookie_t *nodesp; mde_str_cookie_t nname; mde_str_cookie_t aname; int nnodes; int idx; if ((md == NULL) || (nspec == NULL)) return (MDE_INVAL_ELEM_COOKIE); nname = md_find_name(md, nspec->namep); aname = md_find_name(md, "fwd"); nnodes = md_scan_dag(md, NULL, nname, aname, NULL); if (nnodes == 0) return (MDE_INVAL_ELEM_COOKIE); nodesp = kmem_alloc(sizeof (mde_cookie_t) * nnodes, KM_SLEEP); (void) md_scan_dag(md, NULL, nname, aname, nodesp); for (idx = 0; idx < nnodes; idx++) { if (mdeg_node_spec_match(md, nodesp[idx], nspec)) { mde_cookie_t res = nodesp[idx]; kmem_free(nodesp, sizeof (mde_cookie_t) * nnodes); return (res); } } kmem_free(nodesp, sizeof (mde_cookie_t) * nnodes); return (MDE_INVAL_ELEM_COOKIE); }
/* ARGSUSED */ static int pi_enum(topo_mod_t *mod, tnode_t *t_parent, const char *name, topo_instance_t min, topo_instance_t max, void *pi_private, void *data) { int result; int idx; int num_components; size_t csize; hrtime_t starttime; pi_enum_t pi; mde_cookie_t *components; mde_str_cookie_t arc_cookie; mde_str_cookie_t component_cookie; /* Begin enumeration */ starttime = gethrtime(); topo_mod_dprintf(mod, "enumeration starting.\n"); /* Initialize the walker */ result = pi_walker_init(mod); if (result != 0) { (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); return (-1); } /* Open a connection to the LDOM PRI */ bzero(&pi, sizeof (pi_enum_t)); result = pi_ldompri_open(mod, &pi); if (result != 0) { pi_walker_fini(mod); topo_mod_dprintf(mod, "could not open LDOM PRI\n"); (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); return (-1); } pi.mod = mod; /* * Find the top of the components graph in the PRI using the machine * description library. */ num_components = pi_find_mdenodes(mod, pi.mdp, MDE_INVAL_ELEM_COOKIE, MD_STR_COMPONENTS, MD_STR_FWD, &components, &csize); if (num_components < 0 || components == NULL) { /* No nodes were found */ pi_walker_fini(mod); topo_mod_dprintf(mod, "could not find components in PRI\n"); (void) topo_mod_seterrno(mod, EMOD_UKNOWN_ENUM); return (-1); } /* * There should be a single components node. But scan all of the * results just in case a future machine has multiple hierarchies * for some unknown reason. * * We continue to walk components nodes until they are all exhausted * and do not stop if a node cannot be enumerated. Instead, we * enumerate what we can and return a partial-enumeration error if * there is a problem. */ topo_mod_dprintf(mod, "enumerating %d components hierarchies\n", num_components); component_cookie = md_find_name(pi.mdp, MD_STR_COMPONENT); arc_cookie = md_find_name(pi.mdp, MD_STR_FWD); result = 0; for (idx = 0; idx < num_components; idx++) { int skip; /* * We have found a component hierarchy to process. First, * make sure we are not supposed to skip the graph. */ skip = pi_skip_node(mod, pi.mdp, components[idx]); if (skip == 0) { /* * We have found a components node. Find the top- * level nodes and create a topology tree from them. */ result = pi_enum_components(&pi, t_parent, name, components[idx], component_cookie, arc_cookie); } } topo_mod_free(mod, components, csize); /* Close our connection to the PRI */ pi_ldompri_close(mod, &pi); /* Clean up after the walker */ pi_walker_fini(mod); /* Complete enumeration */ topo_mod_dprintf(mod, "enumeration complete in %lld ms.\n", ((gethrtime() - starttime)/MICROSEC)); /* All done */ return (result); }
/* * Routine used to setup a newly inserted CPU in preparation for starting * it running code. */ int mp_cpu_configure(int cpuid) { md_t *mdp; mde_cookie_t rootnode, cpunode = MDE_INVAL_ELEM_COOKIE; int listsz, i; mde_cookie_t *listp = NULL; int num_nodes; uint64_t cpuid_prop; cpu_t *cpu; processorid_t id; ASSERT(MUTEX_HELD(&cpu_lock)); if ((mdp = md_get_handle()) == NULL) return (ENODEV); rootnode = md_root_node(mdp); ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE); num_nodes = md_node_count(mdp); ASSERT(num_nodes > 0); listsz = num_nodes * sizeof (mde_cookie_t); listp = kmem_zalloc(listsz, KM_SLEEP); num_nodes = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"), md_find_name(mdp, "fwd"), listp); if (num_nodes < 0) return (ENODEV); for (i = 0; i < num_nodes; i++) { if (md_get_prop_val(mdp, listp[i], "id", &cpuid_prop)) break; if (cpuid_prop == (uint64_t)cpuid) { cpunode = listp[i]; break; } } if (cpunode == MDE_INVAL_ELEM_COOKIE) return (ENODEV); kmem_free(listp, listsz); mpo_cpu_add(mdp, cpuid); /* * Note: uses cpu_lock to protect cpunodes * which will be modified inside of fill_cpu and * setup_exec_unit_mappings. */ fill_cpu(mdp, cpunode); /* * Adding a CPU may cause the execution unit sharing * relationships to change. Update the mappings in * the cpunode structures. */ setup_chip_mappings(mdp); setup_exec_unit_mappings(mdp); /* propagate the updated mappings to the CPU structures */ for (id = 0; id < NCPU; id++) { if ((cpu = cpu_get(id)) == NULL) continue; cpu_map_exec_units(cpu); } (void) md_fini_handle(mdp); if ((i = setup_cpu_common(cpuid)) != 0) { (void) cleanup_cpu_common(cpuid); return (i); } return (0); }
static int mb_get_pri_info(topo_mod_t *mod, char **serialp, char **partp, char **csnp, char **psnp) { char isa[MAXNAMELEN]; md_t *mdp; mde_cookie_t *listp; uint64_t *bufp; ssize_t bufsize = 0; int nfrus, num_nodes, i; char *pstr = NULL; char *sn, *pn, *dn, *csn, *psn; uint32_t type = 0; ldom_hdl_t *lhp; lhp = ldom_init(mb_topo_alloc, mb_topo_free); if (lhp == NULL) { topo_mod_dprintf(mod, "ldom_init failed\n"); return (-1); } (void) sysinfo(SI_MACHINE, isa, MAXNAMELEN); if (strcmp(isa, "sun4v") != 0) { topo_mod_dprintf(mod, "not sun4v architecture%s\n", isa); ldom_fini(lhp); return (-1); } (void) ldom_get_type(lhp, &type); if ((type & LDOM_TYPE_CONTROL) != 0) { bufsize = ldom_get_core_md(lhp, &bufp); } else { bufsize = ldom_get_local_md(lhp, &bufp); } if (bufsize < 1) { topo_mod_dprintf(mod, "Failed to get the pri/md (bufsize=%d)\n", bufsize); ldom_fini(lhp); return (-1); } topo_mod_dprintf(mod, "pri/md bufsize=%d\n", bufsize); if ((mdp = md_init_intern(bufp, mb_topo_alloc, mb_topo_free)) == NULL || (num_nodes = md_node_count(mdp)) < 1) { topo_mod_dprintf(mod, "md_init_intern error\n"); mb_topo_free(bufp, (size_t)bufsize); ldom_fini(lhp); return (-1); } topo_mod_dprintf(mod, "num_nodes=%d\n", num_nodes); if ((listp = (mde_cookie_t *)mb_topo_alloc( sizeof (mde_cookie_t) * num_nodes)) == NULL) { topo_mod_dprintf(mod, "alloc listp error\n"); mb_topo_free(bufp, (size_t)bufsize); (void) md_fini(mdp); ldom_fini(lhp); return (-1); } nfrus = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE, md_find_name(mdp, "component"), md_find_name(mdp, "fwd"), listp); if (nfrus <= 0) { topo_mod_dprintf(mod, "error: nfrus=%d\n", nfrus); mb_topo_free(listp, sizeof (mde_cookie_t) * num_nodes); mb_topo_free(bufp, (size_t)bufsize); (void) md_fini(mdp); ldom_fini(lhp); return (-1); } topo_mod_dprintf(mod, "nfrus=%d\n", nfrus); sn = pn = dn = psn = csn = NULL; for (i = 0; i < nfrus; i++) { if (md_get_prop_str(mdp, listp[i], "type", &pstr) == 0) { /* systemboard/motherboard component */ if (strcmp("systemboard", pstr) == 0) { if (md_get_prop_str(mdp, listp[i], "serial_number", &sn) < 0) sn = NULL; if (md_get_prop_str(mdp, listp[i], "part_number", &pn) < 0) pn = NULL; if (md_get_prop_str(mdp, listp[i], "dash_number", &dn) < 0) dn = NULL; } else if (strcmp("product", pstr) == 0) { if (md_get_prop_str(mdp, listp[i], "serial_number", &psn) < 0) psn = NULL; } } /* redefined access method for chassis serial number */ if (md_get_prop_str(mdp, listp[i], "nac", &pstr) == 0) { if (strcmp("SYS", pstr) == 0) { if (md_get_prop_str(mdp, listp[i], "serial_number", &csn) < 0) csn = NULL; } } } *serialp = topo_mod_strdup(mod, sn); i = (pn ? strlen(pn) : 0) + (dn ? strlen(dn) : 0) + 1; pstr = mb_topo_alloc(i); (void) snprintf(pstr, i, "%s%s", pn ? pn : "", dn ? dn : ""); *partp = topo_mod_strdup(mod, pstr); mb_topo_free(pstr, i); *csnp = topo_mod_strdup(mod, csn); *psnp = topo_mod_strdup(mod, psn); mb_topo_free(listp, sizeof (mde_cookie_t) * num_nodes); mb_topo_free(bufp, (size_t)bufsize); (void) md_fini(mdp); ldom_fini(lhp); return (0); }
/* * Exported interface to register a LDC endpoint with * the channel nexus */ static int cnex_reg_chan(dev_info_t *dip, uint64_t id, ldc_dev_t devclass) { int idx; cnex_ldc_t *cldcp; cnex_ldc_t *new_cldcp; int listsz, num_nodes, num_channels; md_t *mdp = NULL; mde_cookie_t rootnode, *listp = NULL; uint64_t tmp_id; uint64_t rxino = (uint64_t)-1; uint64_t txino = (uint64_t)-1; cnex_soft_state_t *cnex_ssp; int status, instance; dev_info_t *chan_dip = NULL; /* Get device instance and structure */ instance = ddi_get_instance(dip); cnex_ssp = ddi_get_soft_state(cnex_state, instance); /* Check to see if channel is already registered */ mutex_enter(&cnex_ssp->clist_lock); cldcp = cnex_ssp->clist; while (cldcp) { if (cldcp->id == id) { DWARN("cnex_reg_chan: channel 0x%llx exists\n", id); mutex_exit(&cnex_ssp->clist_lock); return (EINVAL); } cldcp = cldcp->next; } mutex_exit(&cnex_ssp->clist_lock); /* Get the Tx/Rx inos from the MD */ if ((mdp = md_get_handle()) == NULL) { DWARN("cnex_reg_chan: cannot init MD\n"); return (ENXIO); } 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); rootnode = md_root_node(mdp); /* search for all channel_endpoint nodes */ num_channels = md_scan_dag(mdp, rootnode, md_find_name(mdp, "channel-endpoint"), md_find_name(mdp, "fwd"), listp); if (num_channels <= 0) { DWARN("cnex_reg_chan: invalid channel id\n"); kmem_free(listp, listsz); (void) md_fini_handle(mdp); return (EINVAL); } for (idx = 0; idx < num_channels; idx++) { /* Get the channel ID */ status = md_get_prop_val(mdp, listp[idx], "id", &tmp_id); if (status) { DWARN("cnex_reg_chan: cannot read LDC ID\n"); kmem_free(listp, listsz); (void) md_fini_handle(mdp); return (ENXIO); } if (tmp_id != id) continue; /* Get the Tx and Rx ino */ status = md_get_prop_val(mdp, listp[idx], "tx-ino", &txino); if (status) { DWARN("cnex_reg_chan: cannot read Tx ino\n"); kmem_free(listp, listsz); (void) md_fini_handle(mdp); return (ENXIO); } status = md_get_prop_val(mdp, listp[idx], "rx-ino", &rxino); if (status) { DWARN("cnex_reg_chan: cannot read Rx ino\n"); kmem_free(listp, listsz); (void) md_fini_handle(mdp); return (ENXIO); } chan_dip = cnex_find_chan_dip(dip, id, mdp, listp[idx]); ASSERT(chan_dip != NULL); } kmem_free(listp, listsz); (void) md_fini_handle(mdp); /* * check to see if we looped through the list of channel IDs without * matching one (i.e. an 'ino' has not been initialised). */ if ((rxino == -1) || (txino == -1)) { DERR("cnex_reg_chan: no ID matching '%llx' in MD\n", id); return (ENOENT); } /* Allocate a new channel structure */ new_cldcp = kmem_zalloc(sizeof (*new_cldcp), KM_SLEEP); /* Initialize the channel */ mutex_init(&new_cldcp->lock, NULL, MUTEX_DRIVER, NULL); new_cldcp->id = id; new_cldcp->tx.ino = txino; new_cldcp->rx.ino = rxino; new_cldcp->devclass = devclass; new_cldcp->tx.weight = CNEX_TX_INTR_WEIGHT; new_cldcp->rx.weight = cnex_class_weight(devclass); new_cldcp->dip = chan_dip; /* * Add channel to nexus channel list. * Check again to see if channel is already registered since * clist_lock was dropped above. */ mutex_enter(&cnex_ssp->clist_lock); cldcp = cnex_ssp->clist; while (cldcp) { if (cldcp->id == id) { DWARN("cnex_reg_chan: channel 0x%llx exists\n", id); mutex_exit(&cnex_ssp->clist_lock); mutex_destroy(&new_cldcp->lock); kmem_free(new_cldcp, sizeof (*new_cldcp)); return (EINVAL); } cldcp = cldcp->next; } new_cldcp->next = cnex_ssp->clist; cnex_ssp->clist = new_cldcp; mutex_exit(&cnex_ssp->clist_lock); return (0); }
/* * 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); }
/* * Send a notification to a client immediately after it registers. * The result_t is a list of all the nodes that match their specified * nodes of interest, all returned on the added list. This serves * as a base of reference to the client. All future MD updates are * relative to this list. */ static int mdeg_notify_client_reg(mdeg_clnt_t *clnt) { md_t *mdp = NULL; mde_str_cookie_t nname; mde_str_cookie_t aname; mde_cookie_t startnode; int nnodes; int nodechk; mde_cookie_t *listp = NULL; mdeg_result_t *mdeg_res = NULL; int rv = MDEG_SUCCESS; mutex_enter(&mdeg.lock); /* * Handle the special case where the node specification * is NULL. In this case, call the client callback without * any results. All processing is left to the client. */ if (clnt->pspec == NULL) { /* call the client callback */ (*clnt->cb)(clnt->cb_arg, NULL); goto done; } if ((mdp = md_get_handle()) == NULL) { cmn_err(CE_WARN, "unable to retrieve current MD"); rv = MDEG_FAILURE; goto done; } startnode = mdeg_find_start_node(mdp, clnt->pspec); if (startnode == MDE_INVAL_ELEM_COOKIE) { /* not much we can do */ cmn_err(CE_WARN, "unable to match node specifier"); rv = MDEG_FAILURE; goto done; } /* * Use zalloc to provide correct default values for the * unused removed, match_prev, and match_curr lists. */ mdeg_res = kmem_zalloc(sizeof (mdeg_result_t), KM_SLEEP); nname = md_find_name(mdp, clnt->nmatch->namep); aname = md_find_name(mdp, "fwd"); nnodes = md_scan_dag(mdp, startnode, nname, aname, NULL); if (nnodes == 0) { MDEG_DBG("mdeg_notify_client_reg: no nodes of interest\n"); rv = MDEG_SUCCESS; goto done; } else if (nnodes == -1) { MDEG_DBG("error scanning DAG\n"); rv = MDEG_FAILURE; goto done; } MDEG_DBG("mdeg_notify_client_reg: %d node%s of interest\n", nnodes, (nnodes == 1) ? "" : "s"); /* get the list of nodes of interest */ listp = kmem_alloc(sizeof (mde_cookie_t) * nnodes, KM_SLEEP); nodechk = md_scan_dag(mdp, startnode, nname, aname, listp); ASSERT(nodechk == nnodes); mdeg_res->added.mdp = mdp; mdeg_res->added.mdep = listp; mdeg_res->added.nelem = nnodes; /* call the client callback */ (*clnt->cb)(clnt->cb_arg, mdeg_res); done: mutex_exit(&mdeg.lock); if (mdp) (void) md_fini_handle(mdp); if (listp) kmem_free(listp, sizeof (mde_cookie_t) * nnodes); if (mdeg_res) kmem_free(mdeg_res, sizeof (mdeg_result_t)); return (rv); }
int add_cpu_prop(picl_nodehdl_t node, void *args) { mde_cookie_t *cpulistp; mde_cookie_t *cachelistp; mde_cookie_t *tlblistp; int x, num_nodes; int ncpus, ncaches, ntlbs; int status; int reg_prop[SUN4V_CPU_REGSIZE], cpuid; uint64_t int_value; status = ptree_get_propval_by_name(node, OBP_REG, reg_prop, sizeof (reg_prop)); if (status != PICL_SUCCESS) { return (PICL_WALK_TERMINATE); } cpuid = CFGHDL_TO_CPUID(reg_prop[0]); /* * Allocate space for our searches. */ num_nodes = md_node_count(mdp); cpulistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes); if (cpulistp == NULL) { return (PICL_WALK_TERMINATE); } cachelistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes); if (cachelistp == NULL) { return (PICL_WALK_TERMINATE); } tlblistp = (mde_cookie_t *) alloca(sizeof (mde_cookie_t) *num_nodes); if (tlblistp == NULL) { return (PICL_WALK_TERMINATE); } /* * Starting at the root node, scan the "fwd" dag for * all the cpus in this description. */ ncpus = md_scan_dag(mdp, rootnode, md_find_name(mdp, "cpu"), md_find_name(mdp, "fwd"), cpulistp); if (ncpus < 0) { return (PICL_WALK_TERMINATE); } /* * Create PD cpus with a few select properties */ for (x = 0; x < ncpus; x++) { if (md_get_prop_val(mdp, cpulistp[x], "id", &int_value)) { continue; } if (int_value != cpuid) continue; add_md_prop(node, sizeof (int_value), "cpuid", &int_value, PICL_PTYPE_INT); add_md_prop(node, sizeof (int_value), "portid", &int_value, PICL_PTYPE_INT); /* get caches for CPU */ ncaches = md_scan_dag(mdp, cpulistp[x], md_find_name(mdp, "cache"), md_find_name(mdp, "fwd"), cachelistp); add_cache_props(node, cachelistp, ncaches); /* get tlbs for CPU */ ntlbs = md_scan_dag(mdp, cpulistp[x], md_find_name(mdp, "tlb"), md_find_name(mdp, "fwd"), tlblistp); add_tlb_props(node, tlblistp, ntlbs); } return (PICL_WALK_CONTINUE); }
static int cpu_n1_mdesc_init(topo_mod_t *mod, md_t *mdp, md_info_t *chip) { mde_cookie_t *listp; md_cpumap_t *mcmp; int i, num_nodes, idx; uint64_t x; num_nodes = md_node_count(mdp); listp = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * num_nodes); chip->ncpus = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE, md_find_name(mdp, "cpu"), md_find_name(mdp, "fwd"), listp); topo_mod_dprintf(mod, "Found %d cpus\n", chip->ncpus); chip->cpus = topo_mod_zalloc(mod, chip->ncpus * sizeof (md_cpumap_t)); chip->nprocs = chip->ncpus; chip->procs = topo_mod_zalloc(mod, chip->nprocs * sizeof (md_proc_t)); for (idx = 0, mcmp = chip->cpus; idx < chip->ncpus; idx++, mcmp++) { if (md_get_prop_val(mdp, listp[idx], MD_STR_ID, &x) < 0) x = (uint64_t)-1; /* invalid value */ mcmp->cpumap_id = x; if (md_get_prop_val(mdp, listp[idx], MD_STR_PID, &x) < 0) x = mcmp->cpumap_id; mcmp->cpumap_pid = x; mcmp->cpumap_serialno = 0; mcmp->cpumap_chipidx = -1; if (md_get_prop_val(mdp, listp[idx], MD_STR_CPU_SERIAL, &mcmp->cpumap_serialno) < 0) { continue; } if (mcmp->cpumap_serialno == 0) { continue; } /* * This PRI/MD has no indentity info. of the FRU and no * physical proc id. * Find if there is already an existing processor entry * Assign procid based on the order found during reading */ for (i = 0; i < chip->nprocs && chip->procs[i].serialno != 0; i++) { if (mcmp->cpumap_serialno == chip->procs[i].serialno) { break; } } if (i < chip->nprocs) { mcmp->cpumap_chipidx = i; if (chip->procs[i].serialno == 0) { chip->procs[i].id = i; chip->procs[i].serialno = mcmp->cpumap_serialno; topo_mod_dprintf(mod, "chip[%d] serial is %llx\n", i, chip->procs[i].serialno); } } } topo_mod_free(mod, listp, sizeof (mde_cookie_t) * num_nodes); return (0); }
static int cpu_n2_mdesc_init(topo_mod_t *mod, md_t *mdp, md_info_t *chip) { mde_cookie_t *list1p, *list2p; md_cpumap_t *mcmp; md_proc_t *procp; md_fru_t *frup; int i, j, cnt; int procid_flag = 0; int nnode, ncomp, nproc, ncpu; char *str = NULL; uint64_t x, sn; char *strserial, *end; nnode = md_node_count(mdp); list1p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * nnode); /* Count the number of processors and strands */ ncomp = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE, md_find_name(mdp, MD_STR_COMPONENT), md_find_name(mdp, "fwd"), list1p); if (ncomp <= 0) { topo_mod_dprintf(mod, "Component nodes not found\n"); topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); return (-1); } for (i = 0, nproc = 0, ncpu = 0; i < ncomp; i++) { if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 && str != NULL && strcmp(str, MD_STR_PROCESSOR) == 0) { nproc++; /* check if the physical id exists */ if (md_get_prop_val(mdp, list1p[i], MD_STR_ID, &x) == 0) { procid_flag = 1; } } if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) == 0 && str && strcmp(str, MD_STR_STRAND) == 0) { ncpu++; } } topo_mod_dprintf(mod, "Found %d procs and %d strands\n", nproc, ncpu); if (nproc == 0 || ncpu == 0) { topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); return (-1); } /* Alloc processors and strand entries */ list2p = topo_mod_zalloc(mod, sizeof (mde_cookie_t) * 2 * ncpu); chip->nprocs = nproc; chip->procs = topo_mod_zalloc(mod, nproc * sizeof (md_proc_t)); chip->ncpus = ncpu; chip->cpus = topo_mod_zalloc(mod, ncpu * sizeof (md_cpumap_t)); /* Visit each processor node */ procp = chip->procs; mcmp = chip->cpus; for (i = 0, nproc = 0, ncpu = 0; i < ncomp; i++) { if (md_get_prop_str(mdp, list1p[i], MD_STR_TYPE, &str) < 0 || str == NULL || strcmp(str, MD_STR_PROCESSOR)) continue; if (md_get_prop_val(mdp, list1p[i], MD_STR_SERIAL, &sn) < 0) { if (md_get_prop_str(mdp, list1p[i], MD_STR_SERIAL, &strserial) < 0) { topo_mod_dprintf(mod, "Failed to get the serial number of" "proc[%d]\n", nproc); continue; } else { sn = (uint64_t)strtoull(strserial, &end, 16); if (strserial == end) { topo_mod_dprintf(mod, "Failed to convert the serial " "string to serial int of " "proc[%d]\n", nproc); continue; } } } procp->serialno = sn; /* Assign physical proc id */ procp->id = -1; if (procid_flag) { if (md_get_prop_val(mdp, list1p[i], MD_STR_ID, &x) == 0) { procp->id = x; } } else { procp->id = nproc; } topo_mod_dprintf(mod, "proc %d: sn=%llx, id=%d\n", nproc, procp->serialno, procp->id); /* Get all the strands below this proc */ cnt = md_scan_dag(mdp, list1p[i], md_find_name(mdp, MD_STR_COMPONENT), md_find_name(mdp, "fwd"), list2p); topo_mod_dprintf(mod, "proc[%llx]: Found %d fwd components\n", sn, cnt); if (cnt <= 0) { nproc++; procp++; continue; } for (j = 0; j < cnt; j++) { /* Consider only the strand nodes */ if (md_get_prop_str(mdp, list2p[j], MD_STR_TYPE, &str) < 0 || str == NULL || strcmp(str, MD_STR_STRAND)) continue; if (md_get_prop_val(mdp, list2p[j], MD_STR_ID, &x) < 0) x = (uint64_t)-1; /* invalid value */ mcmp->cpumap_id = x; if (md_get_prop_val(mdp, list2p[j], MD_STR_PID, &x) < 0) x = mcmp->cpumap_id; mcmp->cpumap_pid = x; mcmp->cpumap_serialno = sn; mcmp->cpumap_chipidx = nproc; ncpu++; mcmp++; } /* * To get the fru of this proc, follow the back arc up to * find the first node whose fru field is set */ cnt = md_scan_dag(mdp, list1p[i], md_find_name(mdp, MD_STR_COMPONENT), md_find_name(mdp, "back"), list2p); topo_mod_dprintf(mod, "proc[%d]: Found %d back components\n", nproc, cnt); if (cnt <= 0) { nproc++; procp++; continue; } for (j = 0; j < cnt; j++) { /* test the fru field which must be positive number */ if ((md_get_prop_val(mdp, list2p[j], MD_STR_FRU, &x) == 0) && x > 0) break; } if (j < cnt) { /* Found the FRU node, get the fru identity */ topo_mod_dprintf(mod, "proc[%d] sn=%llx has a fru %d\n", nproc, procp->serialno, j); frup = topo_mod_zalloc(mod, sizeof (md_fru_t)); procp->fru = frup; if (!md_get_prop_str(mdp, list2p[j], MD_STR_NAC, &str)) frup->nac = topo_mod_strdup(mod, str); else frup->nac = topo_mod_strdup(mod, MD_FRU_DEF); if (!md_get_prop_str(mdp, list2p[j], MD_STR_PART, &str)) frup->part = topo_mod_strdup(mod, str); if (!md_get_prop_str(mdp, list2p[j], MD_STR_SERIAL, &str)) frup->serial = topo_mod_strdup(mod, str); if (!md_get_prop_str(mdp, list2p[j], MD_STR_DASH, &str)) frup->dash = topo_mod_strdup(mod, str); } else { topo_mod_dprintf(mod, "proc[%d] sn=%llx has no fru\n", i, procp->serialno); } nproc++; procp++; } /* for i */ topo_mod_free(mod, list1p, sizeof (mde_cookie_t) * nnode); topo_mod_free(mod, list2p, sizeof (mde_cookie_t) * 2*chip->ncpus); return (0); }
static int xaui_get_pri_label(topo_mod_t *mod, topo_instance_t n, void *priv, char **labelp) { ldom_hdl_t *hdlp; uint32_t type = 0; ssize_t bufsize = 0; uint64_t *bufp; md_t *mdp; int num_nodes, ncomp; mde_cookie_t *listp; char *pstr = NULL; int i; char *path; /* Get device path minus the device names */ path = xaui_get_path(mod, priv, n); if (path == NULL) { topo_mod_dprintf(mod, "can't get path\n"); return (-1); } hdlp = ldom_init(xaui_topo_alloc, xaui_topo_free); if (hdlp == NULL) { topo_mod_dprintf(mod, "ldom_init failed\n"); return (-1); } (void) ldom_get_type(hdlp, &type); if ((type & LDOM_TYPE_CONTROL) != 0) { bufsize = ldom_get_core_md(hdlp, &bufp); } else { bufsize = ldom_get_local_md(hdlp, &bufp); } if (bufsize < 1) { topo_mod_dprintf(mod, "failed to get pri/md (%d)\n", bufsize); ldom_fini(hdlp); return (-1); } if ((mdp = md_init_intern(bufp, xaui_topo_alloc, xaui_topo_free)) == NULL || (num_nodes = md_node_count(mdp)) < 1) { topo_mod_dprintf(mod, "md_init_intern failed\n"); xaui_topo_free(bufp, (size_t)bufsize); ldom_fini(hdlp); return (-1); } if ((listp = (mde_cookie_t *)xaui_topo_alloc( sizeof (mde_cookie_t) * num_nodes)) == NULL) { topo_mod_dprintf(mod, "can't alloc listp\n"); xaui_topo_free(bufp, (size_t)bufsize); (void) md_fini(mdp); ldom_fini(hdlp); return (-1); } ncomp = md_scan_dag(mdp, MDE_INVAL_ELEM_COOKIE, md_find_name(mdp, "component"), md_find_name(mdp, "fwd"), listp); if (ncomp <= 0) { topo_mod_dprintf(mod, "no component nodes found\n"); xaui_topo_free(listp, sizeof (mde_cookie_t) * num_nodes); xaui_topo_free(bufp, (size_t)bufsize); (void) md_fini(mdp); ldom_fini(hdlp); return (-1); } topo_mod_dprintf(mod, "number of comps (%d)\n", ncomp); for (i = 0; i < ncomp; i++) { /* * Look for type == "io", topo-hc-name == "xaui"; * match "path" md property. */ if ((md_get_prop_str(mdp, listp[i], "type", &pstr) == 0) && (pstr != NULL) && (strncmp(pstr, "io", strlen(pstr)) == 0) && (md_get_prop_str(mdp, listp[i], "topo-hc-name", &pstr) == 0) && (pstr != NULL) && (strncmp(pstr, "xaui", strlen(pstr)) == 0) && (md_get_prop_str(mdp, listp[i], "path", &pstr) == 0) && (pstr != NULL)) { /* check node path */ if (strncmp(pstr, path, sizeof (path)) == 0) { /* this is the node, grab the label */ if (md_get_prop_str(mdp, listp[i], "nac", &pstr) == 0) { *labelp = topo_mod_strdup(mod, pstr); /* need to free this later */ freeprilabel = 1; break; } } } } xaui_topo_free(listp, sizeof (mde_cookie_t) * num_nodes); xaui_topo_free(bufp, (size_t)bufsize); (void) md_fini(mdp); ldom_fini(hdlp); if (path != NULL) { xaui_topo_free(path, strlen(path) + 1); } return (0); }