/* * prom_walk_devs() implements a generic walker for the OBP tree; this * implementation uses an explicitly managed stack in order to save the * overhead of a recursive implementation. */ void prom_walk_devs(pnode_t node, int (*cb)(pnode_t, void *, void *), void *arg, void *result) { pnode_t stack[OBP_STACKDEPTH]; int stackidx = 0; if (node == OBP_NONODE || node == OBP_BADNODE) { prom_panic("Invalid node specified as root of prom tree walk"); } stack[0] = node; for (;;) { pnode_t curnode = stack[stackidx]; pnode_t child; /* * We're out of stuff to do at this level, bump back up a level * in the tree, and move to the next node; if the new level * will be level -1, we're done. */ if (curnode == OBP_NONODE || curnode == OBP_BADNODE) { stackidx--; if (stackidx < 0) return; stack[stackidx] = prom_nextnode(stack[stackidx]); continue; } switch ((*cb)(curnode, arg, result)) { case PROM_WALK_TERMINATE: return; case PROM_WALK_CONTINUE: /* * If curnode has a child, traverse to it, * otherwise move to curnode's sibling. */ child = prom_childnode(curnode); if (child != OBP_NONODE && child != OBP_BADNODE) { stackidx++; stack[stackidx] = child; } else { stack[stackidx] = prom_nextnode(stack[stackidx]); } break; default: prom_panic("unrecognized walk directive"); } } }
/* * Return the root nodeid. * Calling prom_nextnode(0) returns the root nodeid. */ pnode_t prom_rootnode(void) { static pnode_t rootnode; return (rootnode ? rootnode : (rootnode = prom_nextnode(OBP_NONODE))); }
static void have_pmc(pnode_t node) { uint32_t vaddr; pnode_t root; /* * Watchdog property is in the root node. */ root = prom_nextnode((pnode_t)0); if (GETPROPLEN(root, WATCHDOG_ENABLE) != -1) { /* * The hardware watchdog timer resides within logical * unit 8 of SuperI/O. The address property of the node * contains the virtual address that we use to program * the timer. */ if (GETPROP(node, OBP_ADDRESS, (caddr_t)&vaddr) == -1) { watchdog_available = 0; return; } v_pmc_addr_reg = (volatile uint8_t *)(uintptr_t)vaddr; v_pmc_data_reg = (volatile uint8_t *)(uintptr_t)vaddr + 1; watchdog_available = 1; } }
static void create_devinfo_tree(void) { major_t major; pnode_t nodeid; i_ddi_node_cache_init(); #if defined(__sparc) nodeid = prom_nextnode(0); #else /* x86 */ nodeid = DEVI_SID_NODEID; #endif top_devinfo = i_ddi_alloc_node(NULL, rootname, nodeid, -1, NULL, KM_SLEEP); ndi_hold_devi(top_devinfo); /* never release the root */ i_ddi_add_devimap(top_devinfo); /* * Bind root node. * This code is special because root node has no parent */ major = ddi_name_to_major("rootnex"); ASSERT(major != DDI_MAJOR_T_NONE); DEVI(top_devinfo)->devi_major = major; devnamesp[major].dn_head = top_devinfo; i_ddi_set_binding_name(top_devinfo, rootname); i_ddi_set_node_state(top_devinfo, DS_BOUND); /* * Record that devinfos have been made for "rootnex." * di_dfs() is used to read the prom because it doesn't get the * next sibling until the function returns, unlike ddi_walk_devs(). */ di_dfs(ddi_root_node(), get_neighbors, 0); #if !defined(__sparc) /* * On x86, there is no prom. Create device tree by * probing pci config space */ { extern void impl_setup_ddi(void); impl_setup_ddi(); } #endif /* x86 */ }
void map_wellknown_devices() { struct wkdevice *wkp; phandle_t ieeprom; pnode_t root; uint_t stick_freq; /* * if there is a chosen eeprom, note it (for have_eeprom()) */ if (GETPROPLEN(prom_chosennode(), CHOSEN_EEPROM) == sizeof (phandle_t) && GETPROP(prom_chosennode(), CHOSEN_EEPROM, (caddr_t)&ieeprom) != -1) chosen_eeprom = (pnode_t)prom_decode_int(ieeprom); root = prom_nextnode((pnode_t)0); /* * Get System clock frequency from root node if it exists. */ if (GETPROP(root, "stick-frequency", (caddr_t)&stick_freq) != -1) system_clock_freq = stick_freq; map_wellknown(NEXT((pnode_t)0)); /* * See if it worked */ for (wkp = wkdevice; wkp->wk_namep; ++wkp) { if (wkp->wk_flags == V_MUSTHAVE) { cmn_err(CE_PANIC, "map_wellknown_devices: required " "device %s not mapped", wkp->wk_namep); } } /* * all sun4u systems must have an IO bus, i.e. sbus or pcibus */ if (niobus == 0) cmn_err(CE_PANIC, "map_wellknown_devices: no i/o bus node"); check_cpus_ver(); check_cpus_set(); }
/* * find cpu node for the boot processor * * sets globals: * cb_mid */ static pnode_t get_cpu_node(void) { static char *props[] = { "upa-portid", "portid", NULL }; pnode_t node; char *str, *name, **propp; uint_t cpu_id; int err; str = "get_cpu_node"; name = "cpu"; cb_mid = getmid(); for (node = prom_rootnode(); ; node = prom_nextnode(node)) { node = prom_findnode_bydevtype(node, name); if (node == OBP_NONODE) { prom_printf("\n%s: cant find node for devtype \"%s\"\n", str, name); break; } cpu_id = (uint_t)-1; for (propp = props; *propp; propp++) { err = get_intprop(node, *propp, &cpu_id); CB_VPRINTF((" cpu node 0x%x, " "prop \"%s\", cpu_id %d\n", node, *propp, (int)cpu_id)); if (err == 0) break; } if (cpu_id == cb_mid) return (node); } return (OBP_NONODE); }
/* * Platform specific lgroup initialization */ void plat_lgrp_init(void) { pnode_t curnode; char tmp_name[MAXSYSNAME]; int portid; int cpucnt = 0; int max_portid = -1; extern uint32_t lgrp_expand_proc_thresh; extern uint32_t lgrp_expand_proc_diff; extern pgcnt_t lgrp_mem_free_thresh; extern uint32_t lgrp_loadavg_tolerance; extern uint32_t lgrp_loadavg_max_effect; extern uint32_t lgrp_load_thresh; extern lgrp_mem_policy_t lgrp_mem_policy_root; /* * Count the number of CPUs installed to determine if * NUMA optimization should be enabled or not. * * All CPU nodes reside in the root node and have a * device type "cpu". */ curnode = prom_rootnode(); for (curnode = prom_childnode(curnode); curnode; curnode = prom_nextnode(curnode)) { bzero(tmp_name, MAXSYSNAME); if (prom_getprop(curnode, OBP_NAME, (caddr_t)tmp_name) == -1 || prom_getprop(curnode, OBP_DEVICETYPE, tmp_name) == -1 || strcmp(tmp_name, "cpu") != 0) continue; cpucnt++; if (prom_getprop(curnode, "portid", (caddr_t)&portid) != -1 && portid > max_portid) max_portid = portid; } if (cpucnt <= 1) max_mem_nodes = 1; else if (max_portid >= 0 && max_portid < MAX_MEM_NODES) max_mem_nodes = max_portid + 1; /* * Set tuneables for fiesta architecture * * lgrp_expand_proc_thresh is the minimum load on the lgroups * this process is currently running on before considering * expanding threads to another lgroup. * * lgrp_expand_proc_diff determines how much less the remote lgroup * must be loaded before expanding to it. * * Optimize for memory bandwidth by spreading multi-threaded * program to different lgroups. */ lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1; lgrp_expand_proc_diff = lgrp_loadavg_max_effect / 2; lgrp_loadavg_tolerance = lgrp_loadavg_max_effect / 2; lgrp_mem_free_thresh = 1; /* home lgrp must have some memory */ lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1; lgrp_mem_policy_root = LGRP_MEM_POLICY_NEXT; lgrp_load_thresh = 0; mem_node_pfn_shift = ENCHILADA_MC_SHIFT - MMU_PAGESHIFT; }
/*ARGSUSED1*/ static int get_neighbors(dev_info_t *di, int flag) { register int nid, snid, cnid; dev_info_t *parent; char buf[OBP_MAXPROPNAME]; if (di == NULL) return (DDI_WALK_CONTINUE); nid = ddi_get_nodeid(di); snid = cnid = 0; switch (flag) { case DDI_WALK_PRUNESIB: cnid = (int)prom_childnode((pnode_t)nid); break; case DDI_WALK_PRUNECHILD: snid = (int)prom_nextnode((pnode_t)nid); break; case 0: snid = (int)prom_nextnode((pnode_t)nid); cnid = (int)prom_childnode((pnode_t)nid); break; default: return (DDI_WALK_TERMINATE); } if (snid && (snid != -1) && ((parent = ddi_get_parent(di)) != NULL)) { /* * add the first sibling that passes check_status() */ for (; snid && (snid != -1); snid = (int)prom_nextnode((pnode_t)snid)) { if (getlongprop_buf(snid, OBP_NAME, buf, sizeof (buf)) > 0) { if (check_status(snid, buf, parent) == DDI_SUCCESS) { (void) ddi_add_child(parent, buf, snid, -1); break; } } } } if (cnid && (cnid != -1)) { /* * add the first child that passes check_status() */ if (getlongprop_buf(cnid, OBP_NAME, buf, sizeof (buf)) > 0) { if (check_status(cnid, buf, di) == DDI_SUCCESS) { (void) ddi_add_child(di, buf, cnid, -1); } else { for (cnid = (int)prom_nextnode((pnode_t)cnid); cnid && (cnid != -1); cnid = (int)prom_nextnode((pnode_t)cnid)) { if (getlongprop_buf(cnid, OBP_NAME, buf, sizeof (buf)) > 0) { if (check_status(cnid, buf, di) == DDI_SUCCESS) { (void) ddi_add_child( di, buf, cnid, -1); break; } } } } } } return (DDI_WALK_CONTINUE); }
void fill_cpu(pnode_t node) { extern int cpu_get_cpu_unum(int, char *, int, int *); struct cpu_node *cpunode; processorid_t cpuid; int portid; int tlbsize; int size; uint_t clk_freq; pnode_t cmpnode; char namebuf[OBP_MAXPROPNAME], unum[UNUM_NAMLEN]; char *namebufp; int proplen; if ((portid = get_portid(node, &cmpnode)) == -1) { cmn_err(CE_PANIC, "portid not found"); } if (GETPROP(node, "cpuid", (caddr_t)&cpuid) == -1) { cpuid = portid; } if (cpuid < 0 || cpuid >= NCPU) { cmn_err(CE_PANIC, "cpu node %x: cpuid %d out of range", node, cpuid); return; } cpunode = &cpunodes[cpuid]; cpunode->portid = portid; cpunode->nodeid = node; if (cpu_get_cpu_unum(cpuid, unum, UNUM_NAMLEN, &size) != 0) { cpunode->fru_fmri[0] = '\0'; } else { (void) snprintf(cpunode->fru_fmri, sizeof (cpunode->fru_fmri), "%s%s", CPU_FRU_FMRI, unum); } if (cmpnode) { /* * For the CMT case, the parent "core" node contains * properties needed below, use it instead of the * cpu node. */ if ((GETPROP(cmpnode, "device_type", namebuf) > 0) && (strcmp(namebuf, "core") == 0)) { node = cmpnode; } } (void) GETPROP(node, (cmpnode ? "compatible" : "name"), namebuf); /* Make sure CPU name is within boundary and NULL terminated */ proplen = GETPROPLEN(node, (cmpnode ? "compatible" : "name")); ASSERT(proplen > 0 && proplen <= OBP_MAXPROPNAME); if (proplen >= OBP_MAXPROPNAME) proplen = OBP_MAXPROPNAME - 1; namebuf[proplen] = '\0'; namebufp = namebuf; if (strncmp(namebufp, "SUNW,", 5) == 0) namebufp += 5; else if (strncmp(namebufp, "FJSV,", 5) == 0) namebufp += 5; (void) strcpy(cpunode->name, namebufp); (void) GETPROP(node, "implementation#", (caddr_t)&cpunode->implementation); (void) GETPROP(node, "mask#", (caddr_t)&cpunode->version); if (IS_CHEETAH(cpunode->implementation)) { /* remap mask reg */ cpunode->version = REMAP_CHEETAH_MASK(cpunode->version); } if (GETPROP(node, "clock-frequency", (caddr_t)&clk_freq) == -1) { /* * If we didn't find it in the CPU node, look in the root node. */ pnode_t root = prom_nextnode((pnode_t)0); if (GETPROP(root, "clock-frequency", (caddr_t)&clk_freq) == -1) clk_freq = 0; } cpunode->clock_freq = clk_freq; ASSERT(cpunode->clock_freq != 0); /* * Compute scaling factor based on rate of %tick. This is used * to convert from ticks derived from %tick to nanoseconds. See * comment in sun4u/sys/clock.h for details. */ cpunode->tick_nsec_scale = (uint_t)(((uint64_t)NANOSEC << (32 - TICK_NSEC_SHIFT)) / cpunode->clock_freq); (void) GETPROP(node, "#itlb-entries", (caddr_t)&tlbsize); ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ cpunode->itlb_size = (ushort_t)tlbsize; (void) GETPROP(node, "#dtlb-entries", (caddr_t)&tlbsize); ASSERT(tlbsize < USHRT_MAX); /* since we cast it */ cpunode->dtlb_size = (ushort_t)tlbsize; if (cmpnode != OBP_NONODE) { /* * If the CPU has a level 3 cache, then it will be the * external cache. Otherwise the level 2 cache is the * external cache. */ size = 0; (void) GETPROP(node, "l3-cache-size", (caddr_t)&size); if (size <= 0) (void) GETPROP(node, "l2-cache-size", (caddr_t)&size); ASSERT(size != 0); cpunode->ecache_size = size; size = 0; (void) GETPROP(node, "l3-cache-line-size", (caddr_t)&size); if (size <= 0) (void) GETPROP(node, "l2-cache-line-size", (caddr_t)&size); ASSERT(size != 0); cpunode->ecache_linesize = size; size = 0; (void) GETPROP(node, "l2-cache-associativity", (caddr_t)&size); ASSERT(size != 0); cpunode->ecache_associativity = size; cmp_add_cpu(portid, cpuid); } else { size = 0; (void) GETPROP(node, "ecache-size", (caddr_t)&size); ASSERT(size != 0); cpunode->ecache_size = size; size = 0; (void) GETPROP(node, "ecache-line-size", (caddr_t)&size); ASSERT(size != 0); cpunode->ecache_linesize = size; size = 0; (void) GETPROP(node, "ecache-associativity", (caddr_t)&size); ASSERT(size != 0); cpunode->ecache_associativity = size; } /* by default set msram to non-mirrored one */ cpunode->msram = ECACHE_CPU_NON_MIRROR; if (GETPROPLEN(node, "msram") != -1) { cpunode->msram = ECACHE_CPU_MIRROR; } if (GETPROPLEN(node, "msram-observed") != -1) { cpunode->msram = ECACHE_CPU_MIRROR; } if (ncpunode == 0) { cpu_fiximp(node); } cpunode->ecache_setsize = cpunode->ecache_size / cpunode->ecache_associativity; adj_ecache_setsize(cpunode->ecache_setsize); ncpunode++; }