serengeti.c revision 8c754b1b0941ce71249cc956888b3470525b995f
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * CDDL HEADER START
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * The contents of this file are subject to the terms of the
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Common Development and Distribution License (the "License").
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * You may not use this file except in compliance with the License.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * See the License for the specific language governing permissions
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * and limitations under the License.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * When distributing Covered Code, include this CDDL HEADER in each
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * If applicable, add the following below this CDDL HEADER, with the
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * fields enclosed by brackets "[]" replaced with your own identifying
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * information: Portions Copyright [yyyy] [name of copyright owner]
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * CDDL HEADER END
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Use is subject to license terms.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota#pragma ident "%Z%%M% %I% %E% SMI"
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otastatic int sg_debug = 0;
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaint (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota/* local functions */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otastatic void cpu_sgn_update(ushort_t sgn, uchar_t state,
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Local data.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * iosram_write_ptr is a pointer to iosram_write(). Because of
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * kernel dynamic linking, we can't get to the function by name,
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * but we can look up its address, and store it in this variable
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * We include the extern for iosram_write() here not because we call
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * it, but to force compilation errors if its prototype doesn't
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * match the prototype of iosram_write_ptr.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * The same issues apply to iosram_read() and iosram_read_ptr.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaextern int iosram_write (int, uint32_t, caddr_t, uint32_t);
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otastatic int (*iosram_write_ptr)(int, uint32_t, caddr_t, uint32_t) = NULL;
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaextern int iosram_read (int, uint32_t, caddr_t, uint32_t);
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otastatic int (*iosram_read_ptr)(int, uint32_t, caddr_t, uint32_t) = NULL;
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Variable to indicate if the date should be obtained from the SC or not.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaint todsg_use_sc = FALSE; /* set the false at the beginning */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Preallocation of spare tsb's for DR
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * We don't allocate spares for Wildcat since TSBs should come
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * out of memory local to the node.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaint serengeti_tsb_spares = (SG_MAX_IO_BDS * SG_SCHIZO_PER_IO_BD *
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * sg_max_ncpus is the maximum number of CPUs supported on Serengeti.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * sg_max_ncpus is set to be smaller than NCPU to reduce the amount of
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * memory the logs take up until we have a dynamic log memory allocation
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * solution.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaint sg_max_ncpus = (24 * 2); /* (max # of processors * # of cores/proc) */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * variables to control mailbox message timeouts.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * These can be patched via /etc/system or mdb.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaint sbbc_mbox_default_timeout = MBOX_DEFAULT_TIMEOUT;
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota/* cached 'chosen' node_id */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otastatic void (*sg_ecc_taskq_func)(sbbc_ecc_mbox_t *) = NULL;
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otastatic int (*sg_ecc_mbox_func)(sbbc_ecc_mbox_t *) = NULL;
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Table that maps memory slices to a specific memnode.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaplat_dimm_sid_board_t domain_dimm_sids[SG_MAX_CPU_BDS];
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota#endif /* DEBUG */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota /* tod_module_name should be set to "todsg" from OBP property */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota if (tod_module_name && (strcmp(tod_module_name, todsg_name) == 0))
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota#endif /* DEBUG */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota /* Serengeti does not support forthdebug */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Some DR operations require the system to be sync paused.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Sync pause on Serengeti could potentially take up to 4
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * seconds to complete depending on the load on the SC. To
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * avoid send_mond panics during such operations, we need to
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * increase xc_tick_limit to a larger value on Serengeti by
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * setting xc_tick_limit_scale to 5.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota/*ARGSUSED*/
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota (int (*)(struct cpu *))modgetsymvalue("sbdp_cpu_poweron", 0);
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota/*ARGSUSED*/
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota int (*serengeti_cpu_poweroff)(struct cpu *) = NULL;
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota (int (*)(struct cpu *))modgetsymvalue("sbdp_cpu_poweroff", 0);
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota/* Preferred minimum cage size (expressed in pages)... for DR */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota MAX(serengeti_minimum_cage_size, total_pages / 256);
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Post copies obp into the lowest slice. This requires the
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * cage to grow upwards
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota kcage_range_init(phys_avail, KCAGE_UP, preferred_cage_size);
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota /* Only note when the cage is off since it should always be on. */
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota (((uint64_t)(x) + (uint64_t)(a) - 1l) & ~((uint64_t)(a) - 1l)))
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Otaupdate_mem_bounds(int brd, uint64_t base, uint64_t sz)
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * First see if this board already has a memnode associated
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * with it. If not, see if this slice has a memnode. This
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * covers the cases where a single slice covers multiple
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * boards (cross-board interleaving) and where a single
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * board has multiple slices (1+GB DIMMs).
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota if ((mnode = plat_lgrphand_to_mem_node(brd)) == -1) {
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota if ((mnode = slice_to_memnode[PA_2_SLICE(base)]) == -1)
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Align base at 16GB boundary
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Dynamically detect memory slices in the system by decoding
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * the cpu memory decoder registers at boot time.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) < 0) ||
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Decode the board number from the MC portid
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * The "reg" property returns 4 32-bit values. The first two are
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * combined to form a 64-bit address. The second two are for a
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * 64-bit size, but we don't actually need to look at that value.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota prom_printf("Warning: malformed 'reg' property\n");
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota if (prom_getprop(nodeid, "reg", (caddr_t)regs) < 0)
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * Figure out whether the memory controller we are examining
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * belongs to this CPU or a different one.
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota for (i = 0; i < SG_MAX_BANKS_PER_MC; i++) {
c0dd49bdd68c0d758a67d56f07826f3b45cfc664Eiji Ota * If the memory controller is local to this CPU, we use
if (local_mc)
int slice;
int node;
return (node);
plat_lgrp_init(void)
for (i = 0; i < SG_MAX_SLICE; i++) {
switch (evt) {
case LGRP_CONFIG_MEM_ADD:
case LGRP_CONFIG_MEM_DEL:
case LGRP_CONFIG_MEM_RENAME:
find_chosen_dip(void)
sizeof (master_sbbc)) < 0) {
tunnel);
tunnel);
return (dip);
load_platform_drivers(void)
int ret;
(void) find_chosen_dip();
if (watchdog_enable)
if (ret != 0)
char *platform_module_list[] = {
return (SG_MAX_BDS);
return (SG_MAX_IO_PER_BD);
return (SG_MAX_CMPS_PER_BD);
return (SG_MAX_CPUS_PER_BD);
return (SG_MAX_MEM_PER_BD);
plat_max_cpumem_boards(void)
return (SG_MAX_CPU_BDS);
set_platform_max_ncpus(void)
return (sg_max_ncpus);
*swint = 0;
plat_nodename_set(void)
struct nodename_info {
} nni;
if (rv != 0) {
if (rv == 0) {
int sg_use_prom_get_unum = 0;
int sg_use_prom_ecache_unum = 0;
int *lenp)
return (EIO);
return (EINVAL);
if (flt_in_memory) {
if (sg_use_prom_get_unum) {
return (ENOTSUP);
if (sg_use_prom_ecache_unum) {
return (EIO);
return (ENOTSUP);
return (ENOSPC);
return (ENODEV);
return (ENODEV);
switch (msg_type) {
case PLAT_ECC_ERROR_MESSAGE:
case PLAT_ECC_ERROR2_MESSAGE:
log_error = 0;
log_error = 0;
log_error = 0;
log_error = 0;
return (EINVAL);
return (ENOMEM);
return (ENOMEM);
switch (msg_type) {
case PLAT_ECC_ERROR_MESSAGE:
case PLAT_ECC_ERROR2_MESSAGE:
ASSERT(0);
return (EINVAL);
if (cpuid >= 0) {
sizeof (signature));
for (i = 0; i < NCPU; i++) {
sizeof (signature));
sizeof (signature));
startup_platform(void)
int c, neg = 0;
if (!isdigit(c = *p)) {
while (isspace(c))
neg++;
if (!isdigit(c)) {
*pos = p;
*pos = p;
return (neg ? n : -n);
int plen;
sg_prom_sb_dr_check(void)
int rv;
prom_res = 0;
return (prom_res);
sg_prom_cpci_dr_check(void)
return (sg_prom_sb_dr_check());
sg_system_claim(void)
sg_system_release(void)
sg_console_claim(void)
sg_console_release(void)