Пример #1
0
/*
 * 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");
		}
	}
}
Пример #2
0
/*
 * 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)));
}
Пример #3
0
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;
    }
}
Пример #4
0
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 */
}
Пример #5
0
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();
}
Пример #6
0
/*
 * 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);
}
Пример #7
0
/*
 * 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;
}
Пример #8
0
/*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);
}
Пример #9
0
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++;
}