11cb6af97Swnelson /*
21cb6af97Swnelson * CDDL HEADER START
31cb6af97Swnelson *
41cb6af97Swnelson * The contents of this file are subject to the terms of the
5*986fd29aSsetje * Common Development and Distribution License (the "License").
6*986fd29aSsetje * You may not use this file except in compliance with the License.
71cb6af97Swnelson *
81cb6af97Swnelson * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91cb6af97Swnelson * or http://www.opensolaris.org/os/licensing.
101cb6af97Swnelson * See the License for the specific language governing permissions
111cb6af97Swnelson * and limitations under the License.
121cb6af97Swnelson *
131cb6af97Swnelson * When distributing Covered Code, include this CDDL HEADER in each
141cb6af97Swnelson * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151cb6af97Swnelson * If applicable, add the following below this CDDL HEADER, with the
161cb6af97Swnelson * fields enclosed by brackets "[]" replaced with your own identifying
171cb6af97Swnelson * information: Portions Copyright [yyyy] [name of copyright owner]
181cb6af97Swnelson *
191cb6af97Swnelson * CDDL HEADER END
201cb6af97Swnelson */
211cb6af97Swnelson /*
22*986fd29aSsetje * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
231cb6af97Swnelson * Use is subject to license terms.
241cb6af97Swnelson */
251cb6af97Swnelson
261cb6af97Swnelson #pragma ident "%Z%%M% %I% %E% SMI"
271cb6af97Swnelson
281cb6af97Swnelson #include <sys/param.h>
291cb6af97Swnelson #include <sys/systm.h>
301cb6af97Swnelson #include <sys/sysmacros.h>
311cb6af97Swnelson #include <sys/sunddi.h>
321cb6af97Swnelson #include <sys/esunddi.h>
331cb6af97Swnelson #include <sys/platform_module.h>
341cb6af97Swnelson #include <sys/errno.h>
351cb6af97Swnelson #include <sys/lgrp.h>
361cb6af97Swnelson #include <sys/memnode.h>
371cb6af97Swnelson #include <sys/promif.h>
381cb6af97Swnelson
391cb6af97Swnelson int (*p2get_mem_unum)(int, uint64_t, char *, int, int *);
401cb6af97Swnelson
411cb6af97Swnelson void
startup_platform(void)421cb6af97Swnelson startup_platform(void)
431cb6af97Swnelson {
441cb6af97Swnelson }
451cb6af97Swnelson
461cb6af97Swnelson int
set_platform_tsb_spares()471cb6af97Swnelson set_platform_tsb_spares()
481cb6af97Swnelson {
491cb6af97Swnelson return (0);
501cb6af97Swnelson }
511cb6af97Swnelson
521cb6af97Swnelson void
set_platform_defaults(void)531cb6af97Swnelson set_platform_defaults(void)
541cb6af97Swnelson {
551cb6af97Swnelson }
561cb6af97Swnelson
571cb6af97Swnelson /*
581cb6af97Swnelson * Definitions for accessing the pci config space of the isa node
591cb6af97Swnelson * of Southbridge.
601cb6af97Swnelson */
611cb6af97Swnelson #define SCHUMACHER_ISA_PATHNAME "/pci@1e,600000/isa@7"
621cb6af97Swnelson static ddi_acc_handle_t isa_handle; /* handle for isa pci space */
631cb6af97Swnelson
641cb6af97Swnelson
651cb6af97Swnelson void
load_platform_drivers(void)661cb6af97Swnelson load_platform_drivers(void)
671cb6af97Swnelson {
681cb6af97Swnelson dev_info_t *dip; /* dip of the isa driver */
691cb6af97Swnelson
701cb6af97Swnelson /*
711cb6af97Swnelson * Install 'us' driver.
721cb6af97Swnelson */
731cb6af97Swnelson (void) i_ddi_attach_hw_nodes("us");
741cb6af97Swnelson
751cb6af97Swnelson /*
761cb6af97Swnelson * mc-us3i must stay loaded for plat_get_mem_unum()
771cb6af97Swnelson */
781cb6af97Swnelson if (i_ddi_attach_hw_nodes("mc-us3i") != DDI_SUCCESS)
791cb6af97Swnelson cmn_err(CE_WARN, "mc-us3i driver failed to install");
801cb6af97Swnelson (void) ddi_hold_driver(ddi_name_to_major("mc-us3i"));
811cb6af97Swnelson
821cb6af97Swnelson /*
831cb6af97Swnelson * Install Isa driver. This is required for the southbridge IDE
841cb6af97Swnelson * workaround - to reset the IDE channel during IDE bus reset.
851cb6af97Swnelson * Panic the system in case ISA driver could not be loaded or
861cb6af97Swnelson * any problem in accessing its pci config space. Since the register
871cb6af97Swnelson * to reset the channel for IDE is in ISA config space!.
881cb6af97Swnelson */
891cb6af97Swnelson
901cb6af97Swnelson dip = e_ddi_hold_devi_by_path(SCHUMACHER_ISA_PATHNAME, 0);
911cb6af97Swnelson if (dip == NULL) {
921cb6af97Swnelson cmn_err(CE_PANIC, "Could not install the isa driver\n");
931cb6af97Swnelson return;
941cb6af97Swnelson }
951cb6af97Swnelson
961cb6af97Swnelson if (pci_config_setup(dip, &isa_handle) != DDI_SUCCESS) {
971cb6af97Swnelson cmn_err(CE_PANIC, "Could not get the config space of isa\n");
981cb6af97Swnelson return;
991cb6af97Swnelson }
1001cb6af97Swnelson }
1011cb6af97Swnelson
1021cb6af97Swnelson /*
1031cb6af97Swnelson * This routine provides a workaround for a bug in the SB chip which
1041cb6af97Swnelson * can cause data corruption. Will be invoked from the IDE HBA driver for
1051cb6af97Swnelson * Acer SouthBridge at the time of IDE bus reset.
1061cb6af97Swnelson */
1071cb6af97Swnelson /*ARGSUSED*/
1081cb6af97Swnelson int
plat_ide_chipreset(dev_info_t * dip,int chno)1091cb6af97Swnelson plat_ide_chipreset(dev_info_t *dip, int chno)
1101cb6af97Swnelson {
1111cb6af97Swnelson uint8_t val;
1121cb6af97Swnelson int ret = DDI_SUCCESS;
1131cb6af97Swnelson
1141cb6af97Swnelson if (isa_handle == NULL) {
1151cb6af97Swnelson return (DDI_FAILURE);
1161cb6af97Swnelson }
1171cb6af97Swnelson
1181cb6af97Swnelson val = pci_config_get8(isa_handle, 0x58);
1191cb6af97Swnelson /*
1201cb6af97Swnelson * The dip passed as the argument is not used here.
1211cb6af97Swnelson * This will be needed for platforms which have multiple on-board SB,
1221cb6af97Swnelson * The dip passed will be used to match the corresponding ISA node.
1231cb6af97Swnelson */
1241cb6af97Swnelson switch (chno) {
1251cb6af97Swnelson case 0:
1261cb6af97Swnelson /*
1271cb6af97Swnelson * First disable the primary channel then re-enable it.
1281cb6af97Swnelson * As per ALI no wait should be required in between have
1291cb6af97Swnelson * given 1ms delay in between to be on safer side.
1301cb6af97Swnelson * bit 2 of register 0x58 when 0 disable the channel 0.
1311cb6af97Swnelson * bit 2 of register 0x58 when 1 enables the channel 0.
1321cb6af97Swnelson */
1331cb6af97Swnelson pci_config_put8(isa_handle, 0x58, val & 0xFB);
1341cb6af97Swnelson drv_usecwait(1000);
1351cb6af97Swnelson pci_config_put8(isa_handle, 0x58, val);
1361cb6af97Swnelson break;
1371cb6af97Swnelson case 1:
1381cb6af97Swnelson /*
1391cb6af97Swnelson * bit 3 of register 0x58 when 0 disable the channel 1.
1401cb6af97Swnelson * bit 3 of register 0x58 when 1 enables the channel 1.
1411cb6af97Swnelson */
1421cb6af97Swnelson pci_config_put8(isa_handle, 0x58, val & 0xF7);
1431cb6af97Swnelson drv_usecwait(1000);
1441cb6af97Swnelson pci_config_put8(isa_handle, 0x58, val);
1451cb6af97Swnelson break;
1461cb6af97Swnelson default:
1471cb6af97Swnelson /*
1481cb6af97Swnelson * Unknown channel number passed. Return failure.
1491cb6af97Swnelson */
1501cb6af97Swnelson ret = DDI_FAILURE;
1511cb6af97Swnelson }
1521cb6af97Swnelson
1531cb6af97Swnelson return (ret);
1541cb6af97Swnelson }
1551cb6af97Swnelson
1561cb6af97Swnelson
1571cb6af97Swnelson /*ARGSUSED*/
1581cb6af97Swnelson int
plat_cpu_poweron(struct cpu * cp)1591cb6af97Swnelson plat_cpu_poweron(struct cpu *cp)
1601cb6af97Swnelson {
1611cb6af97Swnelson return (ENOTSUP); /* not supported on this platform */
1621cb6af97Swnelson }
1631cb6af97Swnelson
1641cb6af97Swnelson /*ARGSUSED*/
1651cb6af97Swnelson int
plat_cpu_poweroff(struct cpu * cp)1661cb6af97Swnelson plat_cpu_poweroff(struct cpu *cp)
1671cb6af97Swnelson {
1681cb6af97Swnelson return (ENOTSUP); /* not supported on this platform */
1691cb6af97Swnelson }
1701cb6af97Swnelson
1711cb6af97Swnelson /*ARGSUSED*/
1721cb6af97Swnelson void
plat_freelist_process(int mnode)1731cb6af97Swnelson plat_freelist_process(int mnode)
1741cb6af97Swnelson {
1751cb6af97Swnelson }
1761cb6af97Swnelson
1771cb6af97Swnelson char *platform_module_list[] = {
1781cb6af97Swnelson (char *)0
1791cb6af97Swnelson };
1801cb6af97Swnelson
1811cb6af97Swnelson /*ARGSUSED*/
1821cb6af97Swnelson void
plat_tod_fault(enum tod_fault_type tod_bad)1831cb6af97Swnelson plat_tod_fault(enum tod_fault_type tod_bad)
1841cb6af97Swnelson {
1851cb6af97Swnelson }
1861cb6af97Swnelson
1871cb6af97Swnelson /*ARGSUSED*/
1881cb6af97Swnelson int
plat_get_mem_unum(int synd_code,uint64_t flt_addr,int flt_bus_id,int flt_in_memory,ushort_t flt_status,char * buf,int buflen,int * lenp)1891cb6af97Swnelson plat_get_mem_unum(int synd_code, uint64_t flt_addr, int flt_bus_id,
1901cb6af97Swnelson int flt_in_memory, ushort_t flt_status, char *buf, int buflen, int *lenp)
1911cb6af97Swnelson {
1921cb6af97Swnelson if (flt_in_memory && (p2get_mem_unum != NULL))
1931cb6af97Swnelson return (p2get_mem_unum(synd_code, P2ALIGN(flt_addr, 8),
1941cb6af97Swnelson buf, buflen, lenp));
1951cb6af97Swnelson else
1961cb6af97Swnelson return (ENOTSUP);
1971cb6af97Swnelson }
1981cb6af97Swnelson
1991cb6af97Swnelson /*ARGSUSED*/
2001cb6af97Swnelson int
plat_get_cpu_unum(int cpuid,char * buf,int buflen,int * lenp)2011cb6af97Swnelson plat_get_cpu_unum(int cpuid, char *buf, int buflen, int *lenp)
2021cb6af97Swnelson {
2031cb6af97Swnelson if (snprintf(buf, buflen, "MB") >= buflen) {
2041cb6af97Swnelson return (ENOSPC);
2051cb6af97Swnelson } else {
2061cb6af97Swnelson *lenp = strlen(buf);
2071cb6af97Swnelson return (0);
2081cb6af97Swnelson }
2091cb6af97Swnelson }
2101cb6af97Swnelson
2111cb6af97Swnelson /*
2121cb6af97Swnelson * Fiesta support for lgroups.
2131cb6af97Swnelson *
2141cb6af97Swnelson * On fiesta platform, an lgroup platform handle == CPU id
2151cb6af97Swnelson */
2161cb6af97Swnelson
2171cb6af97Swnelson /*
2181cb6af97Swnelson * Macro for extracting the CPU number from the CPU id
2191cb6af97Swnelson */
2201cb6af97Swnelson #define CPUID_TO_LGRP(id) ((id) & 0x7)
2211cb6af97Swnelson #define SCHUMACHER_MC_SHIFT 36
2221cb6af97Swnelson
2231cb6af97Swnelson /*
2241cb6af97Swnelson * Return the platform handle for the lgroup containing the given CPU
2251cb6af97Swnelson */
2261cb6af97Swnelson lgrp_handle_t
plat_lgrp_cpu_to_hand(processorid_t id)2271cb6af97Swnelson plat_lgrp_cpu_to_hand(processorid_t id)
2281cb6af97Swnelson {
2291cb6af97Swnelson return (CPUID_TO_LGRP(id));
2301cb6af97Swnelson }
2311cb6af97Swnelson
2321cb6af97Swnelson /*
2331cb6af97Swnelson * Platform specific lgroup initialization
2341cb6af97Swnelson */
2351cb6af97Swnelson void
plat_lgrp_init(void)2361cb6af97Swnelson plat_lgrp_init(void)
2371cb6af97Swnelson {
238fa9e4066Sahrens pnode_t curnode;
2391cb6af97Swnelson char tmp_name[MAXSYSNAME];
2401cb6af97Swnelson int portid;
2411cb6af97Swnelson int cpucnt = 0;
2421cb6af97Swnelson int max_portid = -1;
2431cb6af97Swnelson extern uint32_t lgrp_expand_proc_thresh;
2441cb6af97Swnelson extern uint32_t lgrp_expand_proc_diff;
2451cb6af97Swnelson extern pgcnt_t lgrp_mem_free_thresh;
2461cb6af97Swnelson extern uint32_t lgrp_loadavg_tolerance;
2471cb6af97Swnelson extern uint32_t lgrp_loadavg_max_effect;
2481cb6af97Swnelson extern uint32_t lgrp_load_thresh;
2491cb6af97Swnelson extern lgrp_mem_policy_t lgrp_mem_policy_root;
2501cb6af97Swnelson
2511cb6af97Swnelson /*
2521cb6af97Swnelson * Count the number of CPUs installed to determine if
2531cb6af97Swnelson * NUMA optimization should be enabled or not.
2541cb6af97Swnelson *
2551cb6af97Swnelson * All CPU nodes reside in the root node and have a
2561cb6af97Swnelson * device type "cpu".
2571cb6af97Swnelson */
2581cb6af97Swnelson curnode = prom_rootnode();
2591cb6af97Swnelson for (curnode = prom_childnode(curnode); curnode;
2601cb6af97Swnelson curnode = prom_nextnode(curnode)) {
2611cb6af97Swnelson bzero(tmp_name, MAXSYSNAME);
2621cb6af97Swnelson if (prom_getprop(curnode, OBP_NAME, (caddr_t)tmp_name) == -1 ||
2631cb6af97Swnelson prom_getprop(curnode, OBP_DEVICETYPE, tmp_name) == -1 ||
2641cb6af97Swnelson strcmp(tmp_name, "cpu") != 0)
2651cb6af97Swnelson continue;
2661cb6af97Swnelson
2671cb6af97Swnelson cpucnt++;
2681cb6af97Swnelson if (prom_getprop(curnode, "portid", (caddr_t)&portid) != -1 &&
2691cb6af97Swnelson portid > max_portid)
2701cb6af97Swnelson max_portid = portid;
2711cb6af97Swnelson }
2721cb6af97Swnelson if (cpucnt <= 1)
2731cb6af97Swnelson max_mem_nodes = 1;
2741cb6af97Swnelson else if (max_portid >= 0 && max_portid < MAX_MEM_NODES)
2751cb6af97Swnelson max_mem_nodes = max_portid + 1;
2761cb6af97Swnelson
2771cb6af97Swnelson /*
2781cb6af97Swnelson * Set tuneables for fiesta architecture
2791cb6af97Swnelson *
2801cb6af97Swnelson * lgrp_expand_proc_thresh is the minimum load on the lgroups
2811cb6af97Swnelson * this process is currently running on before considering
2821cb6af97Swnelson * expanding threads to another lgroup.
2831cb6af97Swnelson *
2841cb6af97Swnelson * lgrp_expand_proc_diff determines how much less the remote lgroup
2851cb6af97Swnelson * must be loaded before expanding to it.
2861cb6af97Swnelson *
2871cb6af97Swnelson * Optimize for memory bandwidth by spreading multi-threaded
2881cb6af97Swnelson * program to different lgroups.
2891cb6af97Swnelson */
2901cb6af97Swnelson lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
2911cb6af97Swnelson lgrp_expand_proc_diff = lgrp_loadavg_max_effect / 2;
2921cb6af97Swnelson lgrp_loadavg_tolerance = lgrp_loadavg_max_effect / 2;
2931cb6af97Swnelson lgrp_mem_free_thresh = 1; /* home lgrp must have some memory */
2941cb6af97Swnelson lgrp_expand_proc_thresh = lgrp_loadavg_max_effect - 1;
2951cb6af97Swnelson lgrp_mem_policy_root = LGRP_MEM_POLICY_NEXT;
2961cb6af97Swnelson lgrp_load_thresh = 0;
2971cb6af97Swnelson
2981cb6af97Swnelson mem_node_pfn_shift = SCHUMACHER_MC_SHIFT - MMU_PAGESHIFT;
2991cb6af97Swnelson }
3001cb6af97Swnelson
3011cb6af97Swnelson /*
3021cb6af97Swnelson * Return latency between "from" and "to" lgroups
3031cb6af97Swnelson *
3041cb6af97Swnelson * This latency number can only be used for relative comparison
3051cb6af97Swnelson * between lgroups on the running system, cannot be used across platforms,
3061cb6af97Swnelson * and may not reflect the actual latency. It is platform and implementation
3071cb6af97Swnelson * specific, so platform gets to decide its value. It would be nice if the
3081cb6af97Swnelson * number was at least proportional to make comparisons more meaningful though.
3091cb6af97Swnelson * NOTE: The numbers below are supposed to be load latencies for uncached
3101cb6af97Swnelson * memory divided by 10.
3111cb6af97Swnelson */
3121cb6af97Swnelson int
plat_lgrp_latency(lgrp_handle_t from,lgrp_handle_t to)3131cb6af97Swnelson plat_lgrp_latency(lgrp_handle_t from, lgrp_handle_t to)
3141cb6af97Swnelson {
3151cb6af97Swnelson /*
3161cb6af97Swnelson * Return remote latency when there are more than two lgroups
3171cb6af97Swnelson * (root and child) and getting latency between two different
3181cb6af97Swnelson * lgroups or root is involved
3191cb6af97Swnelson */
3201cb6af97Swnelson if (lgrp_optimizations() && (from != to ||
3211cb6af97Swnelson from == LGRP_DEFAULT_HANDLE || to == LGRP_DEFAULT_HANDLE))
3221cb6af97Swnelson return (17);
3231cb6af97Swnelson else
3241cb6af97Swnelson return (12);
3251cb6af97Swnelson }
3261cb6af97Swnelson
3271cb6af97Swnelson int
plat_pfn_to_mem_node(pfn_t pfn)3281cb6af97Swnelson plat_pfn_to_mem_node(pfn_t pfn)
3291cb6af97Swnelson {
3301cb6af97Swnelson ASSERT(max_mem_nodes > 1);
3311cb6af97Swnelson return (pfn >> mem_node_pfn_shift);
3321cb6af97Swnelson }
3331cb6af97Swnelson
3341cb6af97Swnelson /*
3351cb6af97Swnelson * Assign memnode to lgroups
3361cb6af97Swnelson */
3371cb6af97Swnelson void
plat_fill_mc(pnode_t nodeid)338fa9e4066Sahrens plat_fill_mc(pnode_t nodeid)
3391cb6af97Swnelson {
3401cb6af97Swnelson int portid;
3411cb6af97Swnelson
3421cb6af97Swnelson /*
3431cb6af97Swnelson * Schumacher memory controller portid == global CPU id
3441cb6af97Swnelson */
3451cb6af97Swnelson if ((prom_getprop(nodeid, "portid", (caddr_t)&portid) == -1) ||
3461cb6af97Swnelson (portid < 0))
3471cb6af97Swnelson return;
3481cb6af97Swnelson
3491cb6af97Swnelson if (portid < max_mem_nodes)
3501cb6af97Swnelson plat_assign_lgrphand_to_mem_node(portid, portid);
3511cb6af97Swnelson }
352