chicago.c revision 5a61720e6468f16cdd018ced5bc5c81626103ee6
2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License, Version 1.0 only
2N/A * (the "License"). You may not use this file except in compliance
2N/A * with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <sys/param.h>
2N/A#include <sys/systm.h>
2N/A#include <sys/sysmacros.h>
2N/A#include <sys/sunddi.h>
2N/A#include <sys/esunddi.h>
2N/A#include <sys/platform_module.h>
2N/A#include <sys/errno.h>
2N/A#include <sys/lgrp.h>
2N/A#include <sys/memnode.h>
2N/A#include <sys/promif.h>
2N/A
2N/A#define SHARED_MI2CV_PATH "/i2c@1f,520000"
2N/Astatic dev_info_t *shared_mi2cv_dip;
2N/Astatic kmutex_t chicago_mi2cv_mutex;
2N/A
2N/Aint (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
2N/A
2N/Avoid
2N/Astartup_platform(void)
2N/A{
2N/A mutex_init(&chicago_mi2cv_mutex, NULL, NULL, NULL);
2N/A}
2N/A
2N/Aint
2N/Aset_platform_tsb_spares()
2N/A{
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/Aset_platform_defaults(void)
2N/A{
2N/A extern char *tod_module_name;
2N/A /* Set appropriate tod module for Chicago */
2N/A if (tod_module_name == NULL)
2N/A tod_module_name = "todds1337";
2N/A}
2N/A
2N/A/*
2N/A * Definitions for accessing the pci config space of the isa node
2N/A * of Southbridge.
2N/A */
2N/Astatic ddi_acc_handle_t isa_handle = NULL; /* handle for isa pci space */
2N/A
2N/A
2N/Avoid
2N/Aload_platform_drivers(void)
2N/A{
2N/A /*
2N/A * Install power driver which handles the power button.
2N/A */
2N/A if (i_ddi_attach_hw_nodes("power") != DDI_SUCCESS)
2N/A cmn_err(CE_WARN, "Failed to install \"power\" driver.");
2N/A (void) ddi_hold_driver(ddi_name_to_major("power"));
2N/A
2N/A /*
2N/A * It is OK to return error because 'us' driver is not available
2N/A * in all clusters (e.g. missing in Core cluster).
2N/A */
2N/A (void) i_ddi_attach_hw_nodes("us");
2N/A
2N/A if (i_ddi_attach_hw_nodes("grbeep") != DDI_SUCCESS)
2N/A cmn_err(CE_WARN, "Failed to install \"beep\" driver.");
2N/A
2N/A
2N/A /*
2N/A * mc-us3i must stay loaded for plat_get_mem_unum()
2N/A */
2N/A if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS)
2N/A cmn_err(CE_WARN, "mc-us3i driver failed to install");
2N/A (void) ddi_hold_driver(ddi_name_to_major("mc-us3i"));
2N/A
2N/A /*
2N/A * Figure out which mi2cv dip is shared with OBP for the nvram
2N/A * device, so the lock can be acquired.
2N/A */
2N/A shared_mi2cv_dip = e_ddi_hold_devi_by_path(SHARED_MI2CV_PATH, 0);
2N/A
2N/A /*
2N/A * todds1337 needs early attach
2N/A */
2N/A if (i_ddi_attach_hw_nodes("todds1337") != DDI_SUCCESS)
2N/A cmn_err(CE_WARN, "todds1337 driver failed to install");
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Aplat_cpu_poweron(struct cpu *cp)
2N/A{
2N/A return (ENOTSUP); /* not supported on this platform */
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Aplat_cpu_poweroff(struct cpu *cp)
2N/A{
2N/A return (ENOTSUP); /* not supported on this platform */
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Avoid
2N/Aplat_freelist_process(int mnode)
2N/A{
2N/A}
2N/A
2N/Achar *platform_module_list[] = {
2N/A "mi2cv",
2N/A "jbusppm",
2N/A "pca9556",
2N/A "ppm",
2N/A (char *)0
2N/A};
2N/A
2N/A/*ARGSUSED*/
2N/Avoid
2N/Aplat_tod_fault(enum tod_fault_type tod_bad)
2N/A{
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Aplat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
2N/A int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
2N/A{
2N/A if (flt_in_memory && (p2get_mem_unum != NULL))
2N/A return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8),
2N/A buf, buflen, lenp));
2N/A else
2N/A return (ENOTSUP);
2N/A}
2N/A
2N/A/*ARGSUSED*/
2N/Aint
2N/Aplat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
2N/A{
2N/A if (snprintf(buf, buflen, "MB") >= buflen) {
2N/A return (ENOSPC);
2N/A } else {
2N/A *lenp = strlen(buf);
2N/A return (0);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Fiesta support for lgroups.
2N/A *
2N/A * On fiesta platform, an lgroup platform handle == CPU id
2N/A */
2N/A
2N/A/*
2N/A * Macro for extracting the CPU number from the CPU id
2N/A */
2N/A#define CPUID_TO_LGRP(id) ((id) & 0x7)
2N/A#define CHICAGO_MC_SHIFT 36
2N/A
2N/A/*
2N/A * Return the platform handle for the lgroup containing the given CPU
2N/A */
2N/Avoid *
2N/Aplat_lgrp_cpu_to_hand(processorid_t id)
2N/A{
2N/A return ((void *) CPUID_TO_LGRP(id));
2N/A}
2N/A
2N/A/*
2N/A * Platform specific lgroup initialization
2N/A */
2N/Avoid
2N/Aplat_lgrp_init(void)
2N/A{
2N/A dnode_t curnode;
2N/A char tmp_name[MAXSYSNAME];
2N/A int portid;
2N/A int cpucnt = 0;
2N/A int max_portid = -1;
2N/A extern uint32_t lgrp_expand_proc_thresh;
2N/A extern uint32_t lgrp_expand_proc_diff;
2N/A extern pgcnt_t lgrp_mem_free_thresh;
2N/A extern uint32_t lgrp_loadavg_tolerance;
2N/A extern uint32_t lgrp_loadavg_max_effect;
2N/A extern uint32_t lgrp_load_thresh;
2N/A extern lgrp_mem_policy_t lgrp_mem_policy_root;
2N/A
2N/A /*
2N/A * Count the number of CPUs installed to determine if
2N/A * NUMA optimization should be enabled or not.
2N/A *
2N/A * All CPU nodes reside in the root node and have a
2N/A * device type "cpu".
2N/A */
2N/A curnode = prom_rootnode();
2N/A for (curnode = prom_childnode(curnode); curnode;
2N/A curnode = prom_nextnode(curnode)) {
2N/A bzero(tmp_name, MAXSYSNAME);
2N/A if (prom_getproplen(curnode, OBP_NAME) < MAXSYSNAME) {
2N/A if (prom_getprop(curnode, OBP_NAME,
2N/A (caddr_t)tmp_name) == -1 || prom_getprop(curnode,
2N/A OBP_DEVICETYPE, tmp_name) == -1 || strcmp(tmp_name,
2N/A "cpu") != 0)
2N/A continue;
2N/A
2N/A cpucnt++;
2N/A if (prom_getprop(curnode, "portid", (caddr_t)&portid) !=
2N/A -1 && portid > max_portid)
2N/A max_portid = portid;
2N/A }
2N/A }
2N/A if (cpucnt <= 1)
2N/A max_mem_nodes = 1;
2N/A else if (max_portid >= 0 && max_portid < MAX_MEM_NODES)
2N/A max_mem_nodes = max_portid + 1;
2N/A
2N/A /*
2N/A * Set tuneables for fiesta architecture
2N/A *
2N/A * lgrp_expand_proc_thresh is the minimum load on the lgroups
2N/A * this process is currently running on before considering
2N/A * expanding threads to another lgroup.
2N/A *
2N/A * lgrp_expand_proc_diff determines how much less the remote lgroup
2N/A * must be loaded before expanding to it.
2N/A *
2N/A * Optimize for memory bandwidth by spreading multi-threaded
2N/A * program to different lgroups.
2N/A */
2N/A lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
2N/A lgrp_expand_proc_diff = lgrp_loadavg_max_effect / 2;
2N/A lgrp_loadavg_tolerance = lgrp_loadavg_max_effect / 2;
2N/A lgrp_mem_free_thresh = 1; /* home lgrp must have some memory */
2N/A lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
2N/A lgrp_mem_policy_root = LGRP_MEM_POLICY_NEXT;
2N/A lgrp_load_thresh = 0;
2N/A
2N/A mem_node_pfn_shift = CHICAGO_MC_SHIFT - MMU_PAGESHIFT;
2N/A}
2N/A
2N/A/*
2N/A * Return latency between "from" and "to" lgroups
2N/A *
2N/A * This latency number can only be used for relative comparison
2N/A * between lgroups on the running system, cannot be used across platforms,
2N/A * and may not reflect the actual latency. It is platform and implementation
2N/A * specific, so platform gets to decide its value. It would be nice if the
2N/A * number was at least proportional to make comparisons more meaningful though.
2N/A * NOTE: The numbers below are supposed to be load latencies for uncached
2N/A * memory divided by 10.
2N/A */
2N/Aint
2N/Aplat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to)
2N/A{
2N/A /*
2N/A * Return remote latency when there are more than two lgroups
2N/A * (root and child) and getting latency between two different
2N/A * lgroups or root is involved
2N/A */
2N/A if (lgrp_optimizations() && (from != to ||
2N/A from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE))
2N/A return (17);
2N/A else
2N/A return (12);
2N/A}
2N/A
2N/Aint
2N/Aplat_pfn_to_mem_node(pfn_t pfn)
2N/A{
2N/A ASSERT(max_mem_nodes > 1);
2N/A return (pfn >> mem_node_pfn_shift);
2N/A}
2N/A
2N/A/*
2N/A * Assign memnode to lgroups
2N/A */
2N/Avoid
2N/Aplat_fill_mc(dnode_t nodeid)
2N/A{
2N/A int portid;
2N/A
2N/A /*
2N/A * Chicago memory controller portid == global CPU id
2N/A */
2N/A if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) == -1) ||
2N/A (portid < 0))
2N/A return;
2N/A
2N/A if (portid < max_mem_nodes)
2N/A plat_assign_lgrphand_to_mem_node((lgrp_handle_t)portid, portid);
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Avoid
2N/Aplat_build_mem_nodes(u_longlong_t *list, size_t nelems)
2N/A{
2N/A size_t elem;
2N/A pfn_t basepfn;
2N/A pgcnt_t npgs;
2N/A
2N/A /*
2N/A * Boot install lists are arranged <addr, len>, <addr, len>, ...
2N/A */
2N/A for (elem = 0; elem < nelems; elem += 2) {
2N/A basepfn = btop(list[elem]);
2N/A npgs = btop(list[elem+1]);
2N/A mem_node_add_slice(basepfn, basepfn + npgs - 1);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Common locking enter code
2N/A */
2N/Avoid
2N/Aplat_setprop_enter(void)
2N/A{
2N/A mutex_enter(&chicago_mi2cv_mutex);
2N/A}
2N/A
2N/A/*
2N/A * Common locking exit code
2N/A */
2N/Avoid
2N/Aplat_setprop_exit(void)
2N/A{
2N/A mutex_exit(&chicago_mi2cv_mutex);
2N/A}
2N/A
2N/A/*
2N/A * Called by mi2cv driver
2N/A */
2N/Avoid
2N/Aplat_shared_i2c_enter(dev_info_t *i2cnexus_dip)
2N/A{
2N/A if (i2cnexus_dip == shared_mi2cv_dip) {
2N/A plat_setprop_enter();
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Called by mi2cv driver
2N/A */
2N/Avoid
2N/Aplat_shared_i2c_exit(dev_info_t *i2cnexus_dip)
2N/A{
2N/A if (i2cnexus_dip == shared_mi2cv_dip) {
2N/A plat_setprop_exit();
2N/A }
2N/A}
2N/A