17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23f47a9c50Smathue * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/types.h> 307c478bd9Sstevel@tonic-gate #include <sys/conf.h> 317c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 327c478bd9Sstevel@tonic-gate #include <sys/stat.h> 337c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 347c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 357c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 377c478bd9Sstevel@tonic-gate #include <sys/errno.h> 387c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 397c478bd9Sstevel@tonic-gate #include <sys/open.h> 407c478bd9Sstevel@tonic-gate #include <sys/thread.h> 417c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 427c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 437c478bd9Sstevel@tonic-gate #include <sys/debug.h> 447c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 457c478bd9Sstevel@tonic-gate #include <sys/ivintr.h> 467c478bd9Sstevel@tonic-gate #include <sys/intr.h> 477c478bd9Sstevel@tonic-gate #include <sys/intreg.h> 487c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 497c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 507c478bd9Sstevel@tonic-gate #include <sys/spl.h> 517c478bd9Sstevel@tonic-gate #include <sys/async.h> 527c478bd9Sstevel@tonic-gate #include <sys/mc.h> 537c478bd9Sstevel@tonic-gate #include <sys/mc-us3.h> 547c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 55*d00f0155Sayznaga #include <sys/platform_module.h> 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* 587c478bd9Sstevel@tonic-gate * Function prototypes 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate static int mc_open(dev_t *, int, int, cred_t *); 627c478bd9Sstevel@tonic-gate static int mc_close(dev_t, int, int, cred_t *); 637c478bd9Sstevel@tonic-gate static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 647c478bd9Sstevel@tonic-gate static int mc_attach(dev_info_t *, ddi_attach_cmd_t); 657c478bd9Sstevel@tonic-gate static int mc_detach(dev_info_t *, ddi_detach_cmd_t); 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * Configuration data structures 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate static struct cb_ops mc_cb_ops = { 717c478bd9Sstevel@tonic-gate mc_open, /* open */ 727c478bd9Sstevel@tonic-gate mc_close, /* close */ 737c478bd9Sstevel@tonic-gate nulldev, /* strategy */ 747c478bd9Sstevel@tonic-gate nulldev, /* print */ 757c478bd9Sstevel@tonic-gate nodev, /* dump */ 767c478bd9Sstevel@tonic-gate nulldev, /* read */ 777c478bd9Sstevel@tonic-gate nulldev, /* write */ 787c478bd9Sstevel@tonic-gate mc_ioctl, /* ioctl */ 797c478bd9Sstevel@tonic-gate nodev, /* devmap */ 807c478bd9Sstevel@tonic-gate nodev, /* mmap */ 817c478bd9Sstevel@tonic-gate nodev, /* segmap */ 827c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 837c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 847c478bd9Sstevel@tonic-gate 0, /* streamtab */ 857c478bd9Sstevel@tonic-gate D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */ 867c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 877c478bd9Sstevel@tonic-gate nodev, /* cb_aread */ 887c478bd9Sstevel@tonic-gate nodev /* cb_awrite */ 897c478bd9Sstevel@tonic-gate }; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate static struct dev_ops mc_ops = { 927c478bd9Sstevel@tonic-gate DEVO_REV, /* rev */ 937c478bd9Sstevel@tonic-gate 0, /* refcnt */ 947c478bd9Sstevel@tonic-gate ddi_getinfo_1to1, /* getinfo */ 957c478bd9Sstevel@tonic-gate nulldev, /* identify */ 967c478bd9Sstevel@tonic-gate nulldev, /* probe */ 977c478bd9Sstevel@tonic-gate mc_attach, /* attach */ 987c478bd9Sstevel@tonic-gate mc_detach, /* detach */ 997c478bd9Sstevel@tonic-gate nulldev, /* reset */ 1007c478bd9Sstevel@tonic-gate &mc_cb_ops, /* cb_ops */ 1017c478bd9Sstevel@tonic-gate (struct bus_ops *)0, /* bus_ops */ 1027c478bd9Sstevel@tonic-gate nulldev /* power */ 1037c478bd9Sstevel@tonic-gate }; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * Driver globals 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate static void *mcp; 1097c478bd9Sstevel@tonic-gate static int nmcs = 0; 1107c478bd9Sstevel@tonic-gate static int seg_id = 0; 1117c478bd9Sstevel@tonic-gate static int nsegments = 0; 1127c478bd9Sstevel@tonic-gate static uint64_t memsize = 0; 1137c478bd9Sstevel@tonic-gate static int maxbanks = 0; 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate static mc_dlist_t *seg_head, *seg_tail, *bank_head, *bank_tail; 1167c478bd9Sstevel@tonic-gate static mc_dlist_t *mctrl_head, *mctrl_tail, *dgrp_head, *dgrp_tail; 1177c478bd9Sstevel@tonic-gate static mc_dlist_t *device_head, *device_tail; 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate static kmutex_t mcmutex; 1207c478bd9Sstevel@tonic-gate static kmutex_t mcdatamutex; 1217c478bd9Sstevel@tonic-gate static int mc_is_open = 0; 1227c478bd9Sstevel@tonic-gate 123*d00f0155Sayznaga static krwlock_t mcdimmsids_rw; 124*d00f0155Sayznaga 125*d00f0155Sayznaga /* pointer to cache of DIMM serial ids */ 126*d00f0155Sayznaga static dimm_sid_cache_t *mc_dimm_sids; 127*d00f0155Sayznaga static int max_entries; 128*d00f0155Sayznaga 1297c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1327c478bd9Sstevel@tonic-gate &mod_driverops, /* module type, this one is a driver */ 1337c478bd9Sstevel@tonic-gate "Memory-controller: %I%", /* module name */ 1347c478bd9Sstevel@tonic-gate &mc_ops, /* driver ops */ 1357c478bd9Sstevel@tonic-gate }; 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1387c478bd9Sstevel@tonic-gate MODREV_1, /* rev */ 1397c478bd9Sstevel@tonic-gate (void *)&modldrv, 1407c478bd9Sstevel@tonic-gate NULL 1417c478bd9Sstevel@tonic-gate }; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate static int mc_get_mem_unum(int synd_code, uint64_t paddr, char *buf, 1447c478bd9Sstevel@tonic-gate int buflen, int *lenp); 1457c478bd9Sstevel@tonic-gate static int mc_get_mem_info(int synd_code, uint64_t paddr, 1467c478bd9Sstevel@tonic-gate uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep, 1477c478bd9Sstevel@tonic-gate int *segsp, int *banksp, int *mcidp); 148*d00f0155Sayznaga static int mc_get_mem_sid(int mcid, int dimm, char *buf, int buflen, int *lenp); 149*d00f0155Sayznaga static int mc_get_mem_offset(uint64_t paddr, uint64_t *offp); 150*d00f0155Sayznaga static int mc_get_mem_addr(int mcid, char *sid, uint64_t off, uint64_t *paddr); 151*d00f0155Sayznaga static int mc_init_sid_cache(void); 1527c478bd9Sstevel@tonic-gate static int mc_get_mcregs(struct mc_soft_state *); 1537c478bd9Sstevel@tonic-gate static void mc_construct(int mc_id, void *dimminfop); 1547c478bd9Sstevel@tonic-gate static int mlayout_add(int mc_id, int bank_no, uint64_t reg, void *dimminfop); 155*d00f0155Sayznaga static void mlayout_del(int mc_id, int delete); 1567c478bd9Sstevel@tonic-gate static struct seg_info *seg_match_base(u_longlong_t base); 1577c478bd9Sstevel@tonic-gate static void mc_node_add(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail); 1587c478bd9Sstevel@tonic-gate static void mc_node_del(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail); 1597c478bd9Sstevel@tonic-gate static mc_dlist_t *mc_node_get(int id, mc_dlist_t *head); 1607c478bd9Sstevel@tonic-gate static void mc_add_mem_unum_label(char *buf, int mcid, int bank, int dimm); 161*d00f0155Sayznaga static int mc_populate_sid_cache(void); 162*d00f0155Sayznaga static int mc_get_sid_cache_index(int mcid); 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate #pragma weak p2get_mem_unum 1657c478bd9Sstevel@tonic-gate #pragma weak p2get_mem_info 166*d00f0155Sayznaga #pragma weak p2get_mem_sid 167*d00f0155Sayznaga #pragma weak p2get_mem_offset 168*d00f0155Sayznaga #pragma weak p2get_mem_addr 169*d00f0155Sayznaga #pragma weak p2init_sid_cache 1707c478bd9Sstevel@tonic-gate #pragma weak plat_add_mem_unum_label 171*d00f0155Sayznaga #pragma weak plat_alloc_sid_cache 172*d00f0155Sayznaga #pragma weak plat_populate_sid_cache 173*d00f0155Sayznaga 174*d00f0155Sayznaga #define QWORD_SIZE 144 175*d00f0155Sayznaga #define QWORD_SIZE_BYTES (QWORD_SIZE / 8) 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate /* 1787c478bd9Sstevel@tonic-gate * These are the module initialization routines. 1797c478bd9Sstevel@tonic-gate */ 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate int 1827c478bd9Sstevel@tonic-gate _init(void) 1837c478bd9Sstevel@tonic-gate { 1847c478bd9Sstevel@tonic-gate int error; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&mcp, 1877c478bd9Sstevel@tonic-gate sizeof (struct mc_soft_state), 1)) != 0) 1887c478bd9Sstevel@tonic-gate return (error); 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate error = mod_install(&modlinkage); 1917c478bd9Sstevel@tonic-gate if (error == 0) { 1927c478bd9Sstevel@tonic-gate mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL); 1937c478bd9Sstevel@tonic-gate mutex_init(&mcdatamutex, NULL, MUTEX_DRIVER, NULL); 194*d00f0155Sayznaga rw_init(&mcdimmsids_rw, NULL, RW_DRIVER, NULL); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate return (error); 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate int 2017c478bd9Sstevel@tonic-gate _fini(void) 2027c478bd9Sstevel@tonic-gate { 2037c478bd9Sstevel@tonic-gate int error; 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) != 0) 2067c478bd9Sstevel@tonic-gate return (error); 2077c478bd9Sstevel@tonic-gate 2087c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&mcp); 2097c478bd9Sstevel@tonic-gate mutex_destroy(&mcmutex); 2107c478bd9Sstevel@tonic-gate mutex_destroy(&mcdatamutex); 211*d00f0155Sayznaga rw_destroy(&mcdimmsids_rw); 212*d00f0155Sayznaga 213*d00f0155Sayznaga if (mc_dimm_sids) 214*d00f0155Sayznaga kmem_free(mc_dimm_sids, sizeof (dimm_sid_cache_t) * 215*d00f0155Sayznaga max_entries); 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate return (0); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate int 2217c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2227c478bd9Sstevel@tonic-gate { 2237c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate static int 2277c478bd9Sstevel@tonic-gate mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2287c478bd9Sstevel@tonic-gate { 2297c478bd9Sstevel@tonic-gate struct mc_soft_state *softsp; 2307c478bd9Sstevel@tonic-gate struct dimm_info *dimminfop; 2317c478bd9Sstevel@tonic-gate int instance, len, err; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* get the instance of this devi */ 2347c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate switch (cmd) { 2377c478bd9Sstevel@tonic-gate case DDI_ATTACH: 2387c478bd9Sstevel@tonic-gate break; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate case DDI_RESUME: 2417c478bd9Sstevel@tonic-gate /* get the soft state pointer for this device node */ 2427c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(mcp, instance); 2437c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc%d: DDI_RESUME: updating MADRs\n", 2447c478bd9Sstevel@tonic-gate instance)); 2457c478bd9Sstevel@tonic-gate /* 2467c478bd9Sstevel@tonic-gate * During resume, the source and target board's bank_infos 2477c478bd9Sstevel@tonic-gate * need to be updated with the new mc MADR values. This is 2487c478bd9Sstevel@tonic-gate * implemented with existing functionality by first removing 2497c478bd9Sstevel@tonic-gate * the props and allocated data structs, and then adding them 2507c478bd9Sstevel@tonic-gate * back in. 2517c478bd9Sstevel@tonic-gate */ 2527c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, softsp->dip, 2537c478bd9Sstevel@tonic-gate DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 2547c478bd9Sstevel@tonic-gate MEM_CFG_PROP_NAME) == 1) { 2557c478bd9Sstevel@tonic-gate (void) ddi_prop_remove(DDI_DEV_T_NONE, softsp->dip, 2567c478bd9Sstevel@tonic-gate MEM_CFG_PROP_NAME); 2577c478bd9Sstevel@tonic-gate } 258*d00f0155Sayznaga mlayout_del(softsp->portid, 0); 2597c478bd9Sstevel@tonic-gate if (mc_get_mcregs(softsp) == -1) { 2607c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mc_attach: mc%d DDI_RESUME failure\n", 2617c478bd9Sstevel@tonic-gate instance); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate default: 2667c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(mcp, instance) != DDI_SUCCESS) 2707c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(mcp, instance); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* Set the dip in the soft state */ 2757c478bd9Sstevel@tonic-gate softsp->dip = devi; 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate if ((softsp->portid = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->dip, 2787c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "portid", -1)) == -1) { 2797c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc%d: unable to get %s property", 2807c478bd9Sstevel@tonic-gate instance, "portid")); 2817c478bd9Sstevel@tonic-gate goto bad; 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc%d ATTACH: portid %d, cpuid %d\n", 2857c478bd9Sstevel@tonic-gate instance, softsp->portid, CPU->cpu_id)); 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* map in the registers for this device. */ 2887c478bd9Sstevel@tonic-gate if (ddi_map_regs(softsp->dip, 0, (caddr_t *)&softsp->mc_base, 0, 0)) { 2897c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc%d: unable to map registers", 2907c478bd9Sstevel@tonic-gate instance)); 2917c478bd9Sstevel@tonic-gate goto bad; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* 2957c478bd9Sstevel@tonic-gate * Get the label of dimms and pin routing information at memory-layout 2967c478bd9Sstevel@tonic-gate * property if the memory controller is enabled. 2977c478bd9Sstevel@tonic-gate * 2987c478bd9Sstevel@tonic-gate * Basically every memory-controller node on every machine should 2997c478bd9Sstevel@tonic-gate * have one of these properties unless the memory controller is 3007c478bd9Sstevel@tonic-gate * physically not capable of having memory attached to it, e.g. 3017c478bd9Sstevel@tonic-gate * Excalibur's slave processor. 3027c478bd9Sstevel@tonic-gate */ 3037c478bd9Sstevel@tonic-gate err = ddi_getlongprop(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS, 3047c478bd9Sstevel@tonic-gate "memory-layout", (caddr_t)&dimminfop, &len); 3057c478bd9Sstevel@tonic-gate if (err == DDI_PROP_SUCCESS) { 3067c478bd9Sstevel@tonic-gate /* 3077c478bd9Sstevel@tonic-gate * Set the pointer and size of property in the soft state 3087c478bd9Sstevel@tonic-gate */ 3097c478bd9Sstevel@tonic-gate softsp->memlayoutp = dimminfop; 3107c478bd9Sstevel@tonic-gate softsp->size = len; 3117c478bd9Sstevel@tonic-gate } else if (err == DDI_PROP_NOT_FOUND) { 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * This is a disable MC. Clear out the pointer and size 3147c478bd9Sstevel@tonic-gate * of property in the soft state 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate softsp->memlayoutp = NULL; 3177c478bd9Sstevel@tonic-gate softsp->size = 0; 3187c478bd9Sstevel@tonic-gate } else { 3197c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc%d is disabled: dimminfop %p\n", 3207c478bd9Sstevel@tonic-gate instance, dimminfop)); 3217c478bd9Sstevel@tonic-gate goto bad2; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 324f47a9c50Smathue DPRINTF(MC_ATTACH_DEBUG, ("mc%d: dimminfop=0x%p data=0x%lx len=%d\n", 325f47a9c50Smathue instance, dimminfop, *(uint64_t *)dimminfop, len)); 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate /* Get MC registers and construct all needed data structure */ 3287c478bd9Sstevel@tonic-gate if (mc_get_mcregs(softsp) == -1) 3297c478bd9Sstevel@tonic-gate goto bad1; 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate mutex_enter(&mcmutex); 3327c478bd9Sstevel@tonic-gate if (nmcs == 1) { 3337c478bd9Sstevel@tonic-gate if (&p2get_mem_unum) 3347c478bd9Sstevel@tonic-gate p2get_mem_unum = mc_get_mem_unum; 3357c478bd9Sstevel@tonic-gate if (&p2get_mem_info) 3367c478bd9Sstevel@tonic-gate p2get_mem_info = mc_get_mem_info; 337*d00f0155Sayznaga if (&p2get_mem_sid) 338*d00f0155Sayznaga p2get_mem_sid = mc_get_mem_sid; 339*d00f0155Sayznaga if (&p2get_mem_offset) 340*d00f0155Sayznaga p2get_mem_offset = mc_get_mem_offset; 341*d00f0155Sayznaga if (&p2get_mem_addr) 342*d00f0155Sayznaga p2get_mem_addr = mc_get_mem_addr; 343*d00f0155Sayznaga if (&p2init_sid_cache) 344*d00f0155Sayznaga p2init_sid_cache = mc_init_sid_cache; 3457c478bd9Sstevel@tonic-gate } 346*d00f0155Sayznaga 3477c478bd9Sstevel@tonic-gate mutex_exit(&mcmutex); 3487c478bd9Sstevel@tonic-gate 349*d00f0155Sayznaga /* 350*d00f0155Sayznaga * Update DIMM serial id information if the DIMM serial id 351*d00f0155Sayznaga * cache has already been initialized. 352*d00f0155Sayznaga */ 353*d00f0155Sayznaga if (mc_dimm_sids) { 354*d00f0155Sayznaga rw_enter(&mcdimmsids_rw, RW_WRITER); 355*d00f0155Sayznaga (void) mc_populate_sid_cache(); 356*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 357*d00f0155Sayznaga } 358*d00f0155Sayznaga 3597c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "mc-us3", S_IFCHR, instance, 3607c478bd9Sstevel@tonic-gate "ddi_mem_ctrl", 0) != DDI_SUCCESS) { 3617c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc_attach: create_minor_node" 3627c478bd9Sstevel@tonic-gate " failed \n")); 3637c478bd9Sstevel@tonic-gate goto bad1; 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 3677c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate bad1: 3707c478bd9Sstevel@tonic-gate /* release all allocated data struture for this MC */ 371*d00f0155Sayznaga mlayout_del(softsp->portid, 0); 3727c478bd9Sstevel@tonic-gate if (softsp->memlayoutp != NULL) 3737c478bd9Sstevel@tonic-gate kmem_free(softsp->memlayoutp, softsp->size); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate /* remove the libdevinfo property */ 3767c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, softsp->dip, 3777c478bd9Sstevel@tonic-gate DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 3787c478bd9Sstevel@tonic-gate MEM_CFG_PROP_NAME) == 1) { 3797c478bd9Sstevel@tonic-gate (void) ddi_prop_remove(DDI_DEV_T_NONE, softsp->dip, 3807c478bd9Sstevel@tonic-gate MEM_CFG_PROP_NAME); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate bad2: 3847c478bd9Sstevel@tonic-gate /* unmap the registers for this device. */ 3857c478bd9Sstevel@tonic-gate ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->mc_base, 0, 0); 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate bad: 3887c478bd9Sstevel@tonic-gate ddi_soft_state_free(mcp, instance); 3897c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3937c478bd9Sstevel@tonic-gate static int 3947c478bd9Sstevel@tonic-gate mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 3957c478bd9Sstevel@tonic-gate { 3967c478bd9Sstevel@tonic-gate int instance; 3977c478bd9Sstevel@tonic-gate struct mc_soft_state *softsp; 3987c478bd9Sstevel@tonic-gate 3997c478bd9Sstevel@tonic-gate /* get the instance of this devi */ 4007c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate /* get the soft state pointer for this device node */ 4037c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(mcp, instance); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate switch (cmd) { 4067c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 4077c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate case DDI_DETACH: 4107c478bd9Sstevel@tonic-gate break; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate default: 4137c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate DPRINTF(MC_DETACH_DEBUG, ("mc%d DETACH: portid= %d, table 0x%p\n", 4177c478bd9Sstevel@tonic-gate instance, softsp->portid, softsp->memlayoutp)); 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* remove the libdevinfo property */ 4207c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, softsp->dip, 4217c478bd9Sstevel@tonic-gate DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 4227c478bd9Sstevel@tonic-gate MEM_CFG_PROP_NAME) == 1) { 4237c478bd9Sstevel@tonic-gate (void) ddi_prop_remove(DDI_DEV_T_NONE, softsp->dip, 4247c478bd9Sstevel@tonic-gate MEM_CFG_PROP_NAME); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* release all allocated data struture for this MC */ 428*d00f0155Sayznaga mlayout_del(softsp->portid, 1); 4297c478bd9Sstevel@tonic-gate if (softsp->memlayoutp != NULL) 4307c478bd9Sstevel@tonic-gate kmem_free(softsp->memlayoutp, softsp->size); 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* unmap the registers */ 4337c478bd9Sstevel@tonic-gate ddi_unmap_regs(softsp->dip, 0, (caddr_t *)&softsp->mc_base, 0, 0); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate mutex_enter(&mcmutex); 4367c478bd9Sstevel@tonic-gate if (nmcs == 0) { 4377c478bd9Sstevel@tonic-gate if (&p2get_mem_unum) 4387c478bd9Sstevel@tonic-gate p2get_mem_unum = NULL; 4397c478bd9Sstevel@tonic-gate if (&p2get_mem_info) 4407c478bd9Sstevel@tonic-gate p2get_mem_info = NULL; 441*d00f0155Sayznaga if (&p2get_mem_sid) 442*d00f0155Sayznaga p2get_mem_sid = NULL; 443*d00f0155Sayznaga if (&p2get_mem_offset) 444*d00f0155Sayznaga p2get_mem_offset = NULL; 445*d00f0155Sayznaga if (&p2get_mem_addr) 446*d00f0155Sayznaga p2get_mem_addr = NULL; 447*d00f0155Sayznaga if (&p2init_sid_cache) 448*d00f0155Sayznaga p2init_sid_cache = NULL; 4497c478bd9Sstevel@tonic-gate } 450*d00f0155Sayznaga 4517c478bd9Sstevel@tonic-gate mutex_exit(&mcmutex); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* free up the soft state */ 4567c478bd9Sstevel@tonic-gate ddi_soft_state_free(mcp, instance); 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4627c478bd9Sstevel@tonic-gate static int 4637c478bd9Sstevel@tonic-gate mc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 4647c478bd9Sstevel@tonic-gate { 4657c478bd9Sstevel@tonic-gate int status = 0; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* verify that otyp is appropriate */ 4687c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) { 4697c478bd9Sstevel@tonic-gate return (EINVAL); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate mutex_enter(&mcmutex); 4737c478bd9Sstevel@tonic-gate if (mc_is_open) { 4747c478bd9Sstevel@tonic-gate status = EBUSY; 4757c478bd9Sstevel@tonic-gate goto bad; 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate mc_is_open = 1; 4787c478bd9Sstevel@tonic-gate bad: 4797c478bd9Sstevel@tonic-gate mutex_exit(&mcmutex); 4807c478bd9Sstevel@tonic-gate return (status); 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4847c478bd9Sstevel@tonic-gate static int 4857c478bd9Sstevel@tonic-gate mc_close(dev_t devp, int flag, int otyp, cred_t *credp) 4867c478bd9Sstevel@tonic-gate { 4877c478bd9Sstevel@tonic-gate mutex_enter(&mcmutex); 4887c478bd9Sstevel@tonic-gate mc_is_open = 0; 4897c478bd9Sstevel@tonic-gate mutex_exit(&mcmutex); 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate return (0); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * cmd includes MCIOC_MEMCONF, MCIOC_MEM, MCIOC_SEG, MCIOC_BANK, MCIOC_DEVGRP, 4967c478bd9Sstevel@tonic-gate * MCIOC_CTRLCONF, MCIOC_CONTROL. 4977c478bd9Sstevel@tonic-gate * 4987c478bd9Sstevel@tonic-gate * MCIOC_MEM, MCIOC_SEG, MCIOC_CTRLCONF, and MCIOC_CONTROL are 4997c478bd9Sstevel@tonic-gate * associated with various length struct. If given number is less than the 5007c478bd9Sstevel@tonic-gate * number in kernel, update the number and return EINVAL so that user could 5017c478bd9Sstevel@tonic-gate * allocate enough space for it. 5027c478bd9Sstevel@tonic-gate * 5037c478bd9Sstevel@tonic-gate */ 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate /* ARGSUSED */ 5067c478bd9Sstevel@tonic-gate static int 5077c478bd9Sstevel@tonic-gate mc_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, 5087c478bd9Sstevel@tonic-gate int *rval_p) 5097c478bd9Sstevel@tonic-gate { 5107c478bd9Sstevel@tonic-gate size_t size; 5117c478bd9Sstevel@tonic-gate struct mc_memconf mcmconf; 5127c478bd9Sstevel@tonic-gate struct mc_memory *mcmem, mcmem_in; 5137c478bd9Sstevel@tonic-gate struct mc_segment *mcseg, mcseg_in; 5147c478bd9Sstevel@tonic-gate struct mc_bank mcbank; 5157c478bd9Sstevel@tonic-gate struct mc_devgrp mcdevgrp; 5167c478bd9Sstevel@tonic-gate struct mc_ctrlconf *mcctrlconf, mcctrlconf_in; 5177c478bd9Sstevel@tonic-gate struct mc_control *mccontrol, mccontrol_in; 5187c478bd9Sstevel@tonic-gate struct seg_info *seg = NULL; 5197c478bd9Sstevel@tonic-gate struct bank_info *bank = NULL; 5207c478bd9Sstevel@tonic-gate struct dgrp_info *dgrp = NULL; 5217c478bd9Sstevel@tonic-gate struct mctrl_info *mcport; 5227c478bd9Sstevel@tonic-gate mc_dlist_t *mctrl; 5237c478bd9Sstevel@tonic-gate int i, status = 0; 5247c478bd9Sstevel@tonic-gate cpu_t *cpu; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate switch (cmd) { 5277c478bd9Sstevel@tonic-gate case MCIOC_MEMCONF: 5287c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate mcmconf.nmcs = nmcs; 5317c478bd9Sstevel@tonic-gate mcmconf.nsegments = nsegments; 5327c478bd9Sstevel@tonic-gate mcmconf.nbanks = maxbanks; 5337c478bd9Sstevel@tonic-gate mcmconf.ndevgrps = NDGRPS; 5347c478bd9Sstevel@tonic-gate mcmconf.ndevs = NDIMMS; 5357c478bd9Sstevel@tonic-gate mcmconf.len_dev = MAX_DEVLEN; 5367c478bd9Sstevel@tonic-gate mcmconf.xfer_size = TRANSFER_SIZE; 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate if (copyout(&mcmconf, (void *)arg, sizeof (struct mc_memconf))) 5417c478bd9Sstevel@tonic-gate return (EFAULT); 5427c478bd9Sstevel@tonic-gate return (0); 5437c478bd9Sstevel@tonic-gate 5447c478bd9Sstevel@tonic-gate /* 5457c478bd9Sstevel@tonic-gate * input: nsegments and allocate space for various length of segmentids 5467c478bd9Sstevel@tonic-gate * 5477c478bd9Sstevel@tonic-gate * return 0: size, number of segments, and all segment ids, 5487c478bd9Sstevel@tonic-gate * where glocal and local ids are identical. 5497c478bd9Sstevel@tonic-gate * EINVAL: if the given nsegments is less than that in kernel and 5507c478bd9Sstevel@tonic-gate * nsegments of struct will be updated. 5517c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate case MCIOC_MEM: 5547c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcmem_in, 5557c478bd9Sstevel@tonic-gate sizeof (struct mc_memory)) != 0) 5567c478bd9Sstevel@tonic-gate return (EFAULT); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 5597c478bd9Sstevel@tonic-gate if (mcmem_in.nsegments < nsegments) { 5607c478bd9Sstevel@tonic-gate mcmem_in.nsegments = nsegments; 5617c478bd9Sstevel@tonic-gate if (copyout(&mcmem_in, (void *)arg, 5627c478bd9Sstevel@tonic-gate sizeof (struct mc_memory))) 5637c478bd9Sstevel@tonic-gate status = EFAULT; 5647c478bd9Sstevel@tonic-gate else 5657c478bd9Sstevel@tonic-gate status = EINVAL; 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 5687c478bd9Sstevel@tonic-gate return (status); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate size = sizeof (struct mc_memory) + (nsegments - 1) * 5727c478bd9Sstevel@tonic-gate sizeof (mcmem->segmentids[0]); 5737c478bd9Sstevel@tonic-gate mcmem = kmem_zalloc(size, KM_SLEEP); 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate mcmem->size = memsize; 5767c478bd9Sstevel@tonic-gate mcmem->nsegments = nsegments; 5777c478bd9Sstevel@tonic-gate seg = (struct seg_info *)seg_head; 5787c478bd9Sstevel@tonic-gate for (i = 0; i < nsegments; i++) { 5797c478bd9Sstevel@tonic-gate ASSERT(seg != NULL); 5807c478bd9Sstevel@tonic-gate mcmem->segmentids[i].globalid = seg->seg_node.id; 5817c478bd9Sstevel@tonic-gate mcmem->segmentids[i].localid = seg->seg_node.id; 5827c478bd9Sstevel@tonic-gate seg = (struct seg_info *)seg->seg_node.next; 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate if (copyout(mcmem, (void *)arg, size)) 5877c478bd9Sstevel@tonic-gate status = EFAULT; 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate kmem_free(mcmem, size); 5907c478bd9Sstevel@tonic-gate return (status); 5917c478bd9Sstevel@tonic-gate 5927c478bd9Sstevel@tonic-gate /* 5937c478bd9Sstevel@tonic-gate * input: id, nbanks and allocate space for various length of bankids 5947c478bd9Sstevel@tonic-gate * 5957c478bd9Sstevel@tonic-gate * return 0: base, size, number of banks, and all bank ids, 5967c478bd9Sstevel@tonic-gate * where global id is unique of all banks and local id 5977c478bd9Sstevel@tonic-gate * is only unique for mc. 5987c478bd9Sstevel@tonic-gate * EINVAL: either id isn't found or if given nbanks is less than 5997c478bd9Sstevel@tonic-gate * that in kernel and nbanks of struct will be updated. 6007c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate case MCIOC_SEG: 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcseg_in, 6057c478bd9Sstevel@tonic-gate sizeof (struct mc_segment)) != 0) 6067c478bd9Sstevel@tonic-gate return (EFAULT); 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 6097c478bd9Sstevel@tonic-gate if ((seg = (struct seg_info *)mc_node_get(mcseg_in.id, 6107c478bd9Sstevel@tonic-gate seg_head)) == NULL) { 6117c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG: seg not match, " 6127c478bd9Sstevel@tonic-gate "id %d\n", mcseg_in.id)); 6137c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6147c478bd9Sstevel@tonic-gate return (EFAULT); 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate if (mcseg_in.nbanks < seg->nbanks) { 6187c478bd9Sstevel@tonic-gate mcseg_in.nbanks = seg->nbanks; 6197c478bd9Sstevel@tonic-gate if (copyout(&mcseg_in, (void *)arg, 6207c478bd9Sstevel@tonic-gate sizeof (struct mc_segment))) 6217c478bd9Sstevel@tonic-gate status = EFAULT; 6227c478bd9Sstevel@tonic-gate else 6237c478bd9Sstevel@tonic-gate status = EINVAL; 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6267c478bd9Sstevel@tonic-gate return (status); 6277c478bd9Sstevel@tonic-gate } 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate size = sizeof (struct mc_segment) + (seg->nbanks - 1) * 6307c478bd9Sstevel@tonic-gate sizeof (mcseg->bankids[0]); 6317c478bd9Sstevel@tonic-gate mcseg = kmem_zalloc(size, KM_SLEEP); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate mcseg->id = seg->seg_node.id; 6347c478bd9Sstevel@tonic-gate mcseg->ifactor = seg->ifactor; 6357c478bd9Sstevel@tonic-gate mcseg->base = seg->base; 6367c478bd9Sstevel@tonic-gate mcseg->size = seg->size; 6377c478bd9Sstevel@tonic-gate mcseg->nbanks = seg->nbanks; 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate bank = seg->hb_inseg; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG:nbanks %d seg 0x%p bank %p\n", 6427c478bd9Sstevel@tonic-gate seg->nbanks, seg, bank)); 6437c478bd9Sstevel@tonic-gate 6447c478bd9Sstevel@tonic-gate i = 0; 6457c478bd9Sstevel@tonic-gate while (bank != NULL) { 6467c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG:idx %d bank_id %d\n", 6477c478bd9Sstevel@tonic-gate i, bank->bank_node.id)); 6487c478bd9Sstevel@tonic-gate mcseg->bankids[i].globalid = bank->bank_node.id; 6497c478bd9Sstevel@tonic-gate mcseg->bankids[i++].localid = 6507c478bd9Sstevel@tonic-gate bank->local_id; 6517c478bd9Sstevel@tonic-gate bank = bank->n_inseg; 6527c478bd9Sstevel@tonic-gate } 6537c478bd9Sstevel@tonic-gate ASSERT(i == seg->nbanks); 6547c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate if (copyout(mcseg, (void *)arg, size)) 6577c478bd9Sstevel@tonic-gate status = EFAULT; 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate kmem_free(mcseg, size); 6607c478bd9Sstevel@tonic-gate return (status); 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /* 6637c478bd9Sstevel@tonic-gate * input: id 6647c478bd9Sstevel@tonic-gate * 6657c478bd9Sstevel@tonic-gate * return 0: mask, match, size, and devgrpid, 6667c478bd9Sstevel@tonic-gate * where global id is unique of all devgrps and local id 6677c478bd9Sstevel@tonic-gate * is only unique for mc. 6687c478bd9Sstevel@tonic-gate * EINVAL: if id isn't found 6697c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 6707c478bd9Sstevel@tonic-gate */ 6717c478bd9Sstevel@tonic-gate case MCIOC_BANK: 6727c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcbank, sizeof (struct mc_bank)) != 0) 6737c478bd9Sstevel@tonic-gate return (EFAULT); 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_BANK: bank id %d\n", mcbank.id)); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate if ((bank = (struct bank_info *)mc_node_get(mcbank.id, 6807c478bd9Sstevel@tonic-gate bank_head)) == NULL) { 6817c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6827c478bd9Sstevel@tonic-gate return (EINVAL); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 685f47a9c50Smathue DPRINTF(MC_CMD_DEBUG, ("MCIOC_BANK: bank %d (0x%p) valid %hu\n", 6867c478bd9Sstevel@tonic-gate bank->bank_node.id, bank, bank->valid)); 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate /* 6897c478bd9Sstevel@tonic-gate * If (Physic Address & MASK) == MATCH, Physic Address is 6907c478bd9Sstevel@tonic-gate * located at this bank. The lower physical address bits 6917c478bd9Sstevel@tonic-gate * are at [9-6]. 6927c478bd9Sstevel@tonic-gate */ 6937c478bd9Sstevel@tonic-gate mcbank.mask = (~(bank->lk | ~(MADR_LK_MASK >> 6947c478bd9Sstevel@tonic-gate MADR_LK_SHIFT))) << MADR_LPA_SHIFT; 6957c478bd9Sstevel@tonic-gate mcbank.match = bank->lm << MADR_LPA_SHIFT; 6967c478bd9Sstevel@tonic-gate mcbank.size = bank->size; 6977c478bd9Sstevel@tonic-gate mcbank.devgrpid.globalid = bank->devgrp_id; 6987c478bd9Sstevel@tonic-gate mcbank.devgrpid.localid = bank->devgrp_id % NDGRPS; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate if (copyout(&mcbank, (void *)arg, sizeof (struct mc_bank))) 7037c478bd9Sstevel@tonic-gate return (EFAULT); 7047c478bd9Sstevel@tonic-gate return (0); 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* 7077c478bd9Sstevel@tonic-gate * input:id and allocate space for various length of deviceids 7087c478bd9Sstevel@tonic-gate * 7097c478bd9Sstevel@tonic-gate * return 0: size and number of devices. 7107c478bd9Sstevel@tonic-gate * EINVAL: id isn't found 7117c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 7127c478bd9Sstevel@tonic-gate */ 7137c478bd9Sstevel@tonic-gate case MCIOC_DEVGRP: 7147c478bd9Sstevel@tonic-gate 7157c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcdevgrp, 7167c478bd9Sstevel@tonic-gate sizeof (struct mc_devgrp)) != 0) 7177c478bd9Sstevel@tonic-gate return (EFAULT); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 7207c478bd9Sstevel@tonic-gate if ((dgrp = (struct dgrp_info *)mc_node_get(mcdevgrp.id, 7217c478bd9Sstevel@tonic-gate dgrp_head)) == NULL) { 7227c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_DEVGRP: not match, id " 7237c478bd9Sstevel@tonic-gate "%d\n", mcdevgrp.id)); 7247c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 7257c478bd9Sstevel@tonic-gate return (EINVAL); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate mcdevgrp.ndevices = dgrp->ndevices; 7297c478bd9Sstevel@tonic-gate mcdevgrp.size = dgrp->size; 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 7327c478bd9Sstevel@tonic-gate 7337c478bd9Sstevel@tonic-gate if (copyout(&mcdevgrp, (void *)arg, sizeof (struct mc_devgrp))) 7347c478bd9Sstevel@tonic-gate status = EFAULT; 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate return (status); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* 7397c478bd9Sstevel@tonic-gate * input: nmcs and allocate space for various length of mcids 7407c478bd9Sstevel@tonic-gate * 7417c478bd9Sstevel@tonic-gate * return 0: number of mc, and all mcids, 7427c478bd9Sstevel@tonic-gate * where glocal and local ids are identical. 7437c478bd9Sstevel@tonic-gate * EINVAL: if the given nmcs is less than that in kernel and 7447c478bd9Sstevel@tonic-gate * nmcs of struct will be updated. 7457c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 7467c478bd9Sstevel@tonic-gate */ 7477c478bd9Sstevel@tonic-gate case MCIOC_CTRLCONF: 7487c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcctrlconf_in, 7497c478bd9Sstevel@tonic-gate sizeof (struct mc_ctrlconf)) != 0) 7507c478bd9Sstevel@tonic-gate return (EFAULT); 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 7537c478bd9Sstevel@tonic-gate if (mcctrlconf_in.nmcs < nmcs) { 7547c478bd9Sstevel@tonic-gate mcctrlconf_in.nmcs = nmcs; 7557c478bd9Sstevel@tonic-gate if (copyout(&mcctrlconf_in, (void *)arg, 7567c478bd9Sstevel@tonic-gate sizeof (struct mc_ctrlconf))) 7577c478bd9Sstevel@tonic-gate status = EFAULT; 7587c478bd9Sstevel@tonic-gate else 7597c478bd9Sstevel@tonic-gate status = EINVAL; 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 7627c478bd9Sstevel@tonic-gate return (status); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate /* 7667c478bd9Sstevel@tonic-gate * Cannot just use the size of the struct because of the various 7677c478bd9Sstevel@tonic-gate * length struct 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate size = sizeof (struct mc_ctrlconf) + ((nmcs - 1) * 7707c478bd9Sstevel@tonic-gate sizeof (mcctrlconf->mcids[0])); 7717c478bd9Sstevel@tonic-gate mcctrlconf = kmem_zalloc(size, KM_SLEEP); 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate mcctrlconf->nmcs = nmcs; 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate /* Get all MC ids and add to mcctrlconf */ 7767c478bd9Sstevel@tonic-gate mctrl = mctrl_head; 7777c478bd9Sstevel@tonic-gate i = 0; 7787c478bd9Sstevel@tonic-gate while (mctrl != NULL) { 7797c478bd9Sstevel@tonic-gate mcctrlconf->mcids[i].globalid = mctrl->id; 7807c478bd9Sstevel@tonic-gate mcctrlconf->mcids[i].localid = mctrl->id; 7817c478bd9Sstevel@tonic-gate i++; 7827c478bd9Sstevel@tonic-gate mctrl = mctrl->next; 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate ASSERT(i == nmcs); 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate if (copyout(mcctrlconf, (void *)arg, size)) 7897c478bd9Sstevel@tonic-gate status = EFAULT; 7907c478bd9Sstevel@tonic-gate 7917c478bd9Sstevel@tonic-gate kmem_free(mcctrlconf, size); 7927c478bd9Sstevel@tonic-gate return (status); 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * input:id, ndevgrps and allocate space for various length of devgrpids 7967c478bd9Sstevel@tonic-gate * 7977c478bd9Sstevel@tonic-gate * return 0: number of devgrp, and all devgrpids, 7987c478bd9Sstevel@tonic-gate * is unique of all devgrps and local id is only unique 7997c478bd9Sstevel@tonic-gate * for mc. 8007c478bd9Sstevel@tonic-gate * EINVAL: either if id isn't found or if the given ndevgrps is 8017c478bd9Sstevel@tonic-gate * less than that in kernel and ndevgrps of struct will 8027c478bd9Sstevel@tonic-gate * be updated. 8037c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 8047c478bd9Sstevel@tonic-gate */ 8057c478bd9Sstevel@tonic-gate case MCIOC_CONTROL: 8067c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mccontrol_in, 8077c478bd9Sstevel@tonic-gate sizeof (struct mc_control)) != 0) 8087c478bd9Sstevel@tonic-gate return (EFAULT); 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 8117c478bd9Sstevel@tonic-gate if ((mcport = (struct mctrl_info *)mc_node_get(mccontrol_in.id, 8127c478bd9Sstevel@tonic-gate mctrl_head)) == NULL) { 8137c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 8147c478bd9Sstevel@tonic-gate return (EINVAL); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * mcport->ndevgrps zero means Memory Controller is disable. 8197c478bd9Sstevel@tonic-gate */ 8207c478bd9Sstevel@tonic-gate if ((mccontrol_in.ndevgrps < mcport->ndevgrps) || 8217c478bd9Sstevel@tonic-gate (mcport->ndevgrps == 0)) { 8227c478bd9Sstevel@tonic-gate mccontrol_in.ndevgrps = mcport->ndevgrps; 8237c478bd9Sstevel@tonic-gate if (copyout(&mccontrol_in, (void *)arg, 8247c478bd9Sstevel@tonic-gate sizeof (struct mc_control))) 8257c478bd9Sstevel@tonic-gate status = EFAULT; 8267c478bd9Sstevel@tonic-gate else if (mcport->ndevgrps != 0) 8277c478bd9Sstevel@tonic-gate status = EINVAL; 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 8307c478bd9Sstevel@tonic-gate return (status); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate size = sizeof (struct mc_control) + (mcport->ndevgrps - 1) * 8347c478bd9Sstevel@tonic-gate sizeof (mccontrol->devgrpids[0]); 8357c478bd9Sstevel@tonic-gate mccontrol = kmem_zalloc(size, KM_SLEEP); 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate mccontrol->id = mcport->mctrl_node.id; 8387c478bd9Sstevel@tonic-gate mccontrol->ndevgrps = mcport->ndevgrps; 8397c478bd9Sstevel@tonic-gate for (i = 0; i < mcport->ndevgrps; i++) { 8407c478bd9Sstevel@tonic-gate mccontrol->devgrpids[i].globalid = mcport->devgrpids[i]; 8417c478bd9Sstevel@tonic-gate mccontrol->devgrpids[i].localid = 8427c478bd9Sstevel@tonic-gate mcport->devgrpids[i] % NDGRPS; 843f47a9c50Smathue DPRINTF(MC_CMD_DEBUG, ("MCIOC_CONTROL: devgrp id %lu\n", 844f47a9c50Smathue *(uint64_t *)&mccontrol->devgrpids[i])); 8457c478bd9Sstevel@tonic-gate } 8467c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate if (copyout(mccontrol, (void *)arg, size)) 8497c478bd9Sstevel@tonic-gate status = EFAULT; 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate kmem_free(mccontrol, size); 8527c478bd9Sstevel@tonic-gate return (status); 8537c478bd9Sstevel@tonic-gate 8547c478bd9Sstevel@tonic-gate /* 8557c478bd9Sstevel@tonic-gate * input:id 8567c478bd9Sstevel@tonic-gate * 8577c478bd9Sstevel@tonic-gate * return 0: CPU flushed successfully. 8587c478bd9Sstevel@tonic-gate * EINVAL: the id wasn't found 8597c478bd9Sstevel@tonic-gate */ 8607c478bd9Sstevel@tonic-gate case MCIOC_ECFLUSH: 8617c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 8627c478bd9Sstevel@tonic-gate cpu = cpu_get((processorid_t)arg); 8637c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 8647c478bd9Sstevel@tonic-gate if (cpu == NULL) 8657c478bd9Sstevel@tonic-gate return (EINVAL); 8667c478bd9Sstevel@tonic-gate 8677c478bd9Sstevel@tonic-gate xc_one(arg, (xcfunc_t *)cpu_flush_ecache, 0, 0); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate return (0); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate default: 8727c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("DEFAULT: cmd is wrong\n")); 8737c478bd9Sstevel@tonic-gate return (EFAULT); 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate /* 8787c478bd9Sstevel@tonic-gate * Get Memory Address Decoding Registers and construct list. 8797c478bd9Sstevel@tonic-gate * flag is to workaround Cheetah's restriction where register cannot be mapped 8807c478bd9Sstevel@tonic-gate * if port id(MC registers on it) == cpu id(process is running on it). 8817c478bd9Sstevel@tonic-gate */ 8827c478bd9Sstevel@tonic-gate static int 8837c478bd9Sstevel@tonic-gate mc_get_mcregs(struct mc_soft_state *softsp) 8847c478bd9Sstevel@tonic-gate { 8857c478bd9Sstevel@tonic-gate int i; 8867c478bd9Sstevel@tonic-gate int err = 0; 8877c478bd9Sstevel@tonic-gate uint64_t madreg; 8887c478bd9Sstevel@tonic-gate uint64_t ma_reg_array[NBANKS]; /* there are NBANKS of madrs */ 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /* Construct lists for MC, mctrl_info, dgrp_info, and device_info */ 8917c478bd9Sstevel@tonic-gate mc_construct(softsp->portid, softsp->memlayoutp); 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* 8947c478bd9Sstevel@tonic-gate * If memlayoutp is NULL, the Memory Controller is disable, and 8957c478bd9Sstevel@tonic-gate * doesn't need to create any bank and segment. 8967c478bd9Sstevel@tonic-gate */ 8977c478bd9Sstevel@tonic-gate if (softsp->memlayoutp == NULL) 8987c478bd9Sstevel@tonic-gate goto exit; 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate /* 9017c478bd9Sstevel@tonic-gate * Get the content of 4 Memory Address Decoding Registers, and 9027c478bd9Sstevel@tonic-gate * construct lists of logical banks and segments. 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate for (i = 0; i < NBANKS; i++) { 9057c478bd9Sstevel@tonic-gate DPRINTF(MC_REG_DEBUG, ("get_mcregs: mapreg=0x%p portid=%d " 9067c478bd9Sstevel@tonic-gate "cpu=%d\n", softsp->mc_base, softsp->portid, CPU->cpu_id)); 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate kpreempt_disable(); 9097c478bd9Sstevel@tonic-gate if (softsp->portid == (cpunodes[CPU->cpu_id].portid)) 9107c478bd9Sstevel@tonic-gate madreg = get_mcr(MADR0OFFSET + (i * REGOFFSET)); 9117c478bd9Sstevel@tonic-gate else 9127c478bd9Sstevel@tonic-gate madreg = *((uint64_t *)(softsp->mc_base + MADR0OFFSET + 9137c478bd9Sstevel@tonic-gate (i * REGOFFSET))); 9147c478bd9Sstevel@tonic-gate kpreempt_enable(); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate DPRINTF(MC_REG_DEBUG, ("get_mcregs 2: memlayoutp=0x%p madreg " 917f47a9c50Smathue "reg=0x%lx\n", softsp->memlayoutp, madreg)); 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate ma_reg_array[i] = madreg; 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate if ((err = mlayout_add(softsp->portid, i, madreg, 9227c478bd9Sstevel@tonic-gate softsp->memlayoutp)) == -1) 9237c478bd9Sstevel@tonic-gate break; 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate * Create the logical bank property for this mc node. This 9287c478bd9Sstevel@tonic-gate * property is an encoded array of the madr for each logical 9297c478bd9Sstevel@tonic-gate * bank (there are NBANKS of these). 9307c478bd9Sstevel@tonic-gate */ 9317c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, softsp->dip, 9327c478bd9Sstevel@tonic-gate DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, 9337c478bd9Sstevel@tonic-gate MEM_CFG_PROP_NAME) != 1) { 9347c478bd9Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, softsp->dip, 9357c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, MEM_CFG_PROP_NAME, 9367c478bd9Sstevel@tonic-gate (caddr_t)&ma_reg_array, sizeof (ma_reg_array)); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate exit: 9407c478bd9Sstevel@tonic-gate if (!err) { 9417c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 9427c478bd9Sstevel@tonic-gate nmcs++; 9437c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate return (err); 9467c478bd9Sstevel@tonic-gate } 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate /* 949*d00f0155Sayznaga * Translate a <DIMM, offset> pair to a physical address. 950*d00f0155Sayznaga */ 951*d00f0155Sayznaga static int 952*d00f0155Sayznaga mc_offset_to_addr(struct seg_info *seg, 953*d00f0155Sayznaga struct bank_info *bank, uint64_t off, uint64_t *addr) 954*d00f0155Sayznaga { 955*d00f0155Sayznaga uint64_t base, size, line, remainder; 956*d00f0155Sayznaga uint32_t ifactor; 957*d00f0155Sayznaga 958*d00f0155Sayznaga /* 959*d00f0155Sayznaga * Compute the half-dimm size in bytes. 960*d00f0155Sayznaga * Note that bank->size represents the number of data bytes, 961*d00f0155Sayznaga * and does not include the additional bits used for ecc, mtag, 962*d00f0155Sayznaga * and mtag ecc information in each 144-bit checkword. 963*d00f0155Sayznaga * For calculating the offset to a checkword we need the size 964*d00f0155Sayznaga * including the additional 8 bytes for each 64 data bytes of 965*d00f0155Sayznaga * a cache line. 966*d00f0155Sayznaga */ 967*d00f0155Sayznaga size = ((bank->size / 4) / 64) * 72; 968*d00f0155Sayznaga 969*d00f0155Sayznaga /* 970*d00f0155Sayznaga * Check if the offset is within this bank. This depends on the position 971*d00f0155Sayznaga * of the bank, i.e., whether it is the front bank or the back bank. 972*d00f0155Sayznaga */ 973*d00f0155Sayznaga base = size * bank->pos; 974*d00f0155Sayznaga 975*d00f0155Sayznaga if ((off < base) || (off >= (base + size))) 976*d00f0155Sayznaga return (-1); 977*d00f0155Sayznaga 978*d00f0155Sayznaga /* 979*d00f0155Sayznaga * Compute the offset within the half-dimm. 980*d00f0155Sayznaga */ 981*d00f0155Sayznaga off -= base; 982*d00f0155Sayznaga 983*d00f0155Sayznaga /* 984*d00f0155Sayznaga * Compute the line within the half-dimm. This is the same as the line 985*d00f0155Sayznaga * within the bank since each DIMM in a bank contributes uniformly 986*d00f0155Sayznaga * 144 bits (18 bytes) to a cache line. 987*d00f0155Sayznaga */ 988*d00f0155Sayznaga line = off / QWORD_SIZE_BYTES; 989*d00f0155Sayznaga 990*d00f0155Sayznaga remainder = off % QWORD_SIZE_BYTES; 991*d00f0155Sayznaga 992*d00f0155Sayznaga /* 993*d00f0155Sayznaga * Compute the line within the segment. 994*d00f0155Sayznaga * The bank->lm field indicates the order in which cache lines are 995*d00f0155Sayznaga * distributed across the banks of a segment (See the Cheetah PRM). 996*d00f0155Sayznaga * The interleave factor the bank is programmed with is used instead 997*d00f0155Sayznaga * of the segment interleave factor since a segment can be composed 998*d00f0155Sayznaga * of banks with different interleave factors if the banks are not 999*d00f0155Sayznaga * uniform in size. 1000*d00f0155Sayznaga */ 1001*d00f0155Sayznaga ifactor = (bank->lk ^ 0xF) + 1; 1002*d00f0155Sayznaga line = (line * ifactor) + bank->lm; 1003*d00f0155Sayznaga 1004*d00f0155Sayznaga /* 1005*d00f0155Sayznaga * Compute the physical address assuming that there are 64 data bytes 1006*d00f0155Sayznaga * in a cache line. 1007*d00f0155Sayznaga */ 1008*d00f0155Sayznaga *addr = (line << 6) + seg->base; 1009*d00f0155Sayznaga *addr += remainder * 16; 1010*d00f0155Sayznaga 1011*d00f0155Sayznaga return (0); 1012*d00f0155Sayznaga } 1013*d00f0155Sayznaga 1014*d00f0155Sayznaga /* 1015*d00f0155Sayznaga * Translate a physical address to a <DIMM, offset> pair. 1016*d00f0155Sayznaga */ 1017*d00f0155Sayznaga static void 1018*d00f0155Sayznaga mc_addr_to_offset(struct seg_info *seg, 1019*d00f0155Sayznaga struct bank_info *bank, uint64_t addr, uint64_t *off) 1020*d00f0155Sayznaga { 1021*d00f0155Sayznaga uint64_t base, size, line, remainder; 1022*d00f0155Sayznaga uint32_t ifactor; 1023*d00f0155Sayznaga 1024*d00f0155Sayznaga /* 1025*d00f0155Sayznaga * Compute the line within the segment assuming that there are 64 data 1026*d00f0155Sayznaga * bytes in a cache line. 1027*d00f0155Sayznaga */ 1028*d00f0155Sayznaga line = (addr - seg->base) / 64; 1029*d00f0155Sayznaga 1030*d00f0155Sayznaga /* 1031*d00f0155Sayznaga * The lm (lower match) field from the Memory Address Decoding Register 1032*d00f0155Sayznaga * for this bank determines which lines within a memory segment this 1033*d00f0155Sayznaga * bank should respond to. These are the actual address bits the 1034*d00f0155Sayznaga * interleave is done over (See the Cheetah PRM). 1035*d00f0155Sayznaga * In other words, the lm field indicates the order in which the cache 1036*d00f0155Sayznaga * lines are distributed across the banks of a segment, and thusly it 1037*d00f0155Sayznaga * can be used to compute the line within this bank. This is the same as 1038*d00f0155Sayznaga * the line within the half-dimm. This is because each DIMM in a bank 1039*d00f0155Sayznaga * contributes uniformly to every cache line. 1040*d00f0155Sayznaga */ 1041*d00f0155Sayznaga ifactor = (bank->lk ^ 0xF) + 1; 1042*d00f0155Sayznaga line = (line - bank->lm)/ifactor; 1043*d00f0155Sayznaga 1044*d00f0155Sayznaga /* 1045*d00f0155Sayznaga * Compute the offset within the half-dimm. This depends on whether 1046*d00f0155Sayznaga * or not the bank is a front logical bank or a back logical bank. 1047*d00f0155Sayznaga */ 1048*d00f0155Sayznaga *off = line * QWORD_SIZE_BYTES; 1049*d00f0155Sayznaga 1050*d00f0155Sayznaga /* 1051*d00f0155Sayznaga * Compute the half-dimm size in bytes. 1052*d00f0155Sayznaga * Note that bank->size represents the number of data bytes, 1053*d00f0155Sayznaga * and does not include the additional bits used for ecc, mtag, 1054*d00f0155Sayznaga * and mtag ecc information in each 144-bit quadword. 1055*d00f0155Sayznaga * For calculating the offset to a checkword we need the size 1056*d00f0155Sayznaga * including the additional 8 bytes for each 64 data bytes of 1057*d00f0155Sayznaga * a cache line. 1058*d00f0155Sayznaga */ 1059*d00f0155Sayznaga size = ((bank->size / 4) / 64) * 72; 1060*d00f0155Sayznaga 1061*d00f0155Sayznaga /* 1062*d00f0155Sayznaga * Compute the offset within the dimm to the nearest line. This depends 1063*d00f0155Sayznaga * on whether or not the bank is a front logical bank or a back logical 1064*d00f0155Sayznaga * bank. 1065*d00f0155Sayznaga */ 1066*d00f0155Sayznaga base = size * bank->pos; 1067*d00f0155Sayznaga *off += base; 1068*d00f0155Sayznaga 1069*d00f0155Sayznaga remainder = (addr - seg->base) % 64; 1070*d00f0155Sayznaga remainder /= 16; 1071*d00f0155Sayznaga *off += remainder; 1072*d00f0155Sayznaga } 1073*d00f0155Sayznaga 1074*d00f0155Sayznaga /* 10757c478bd9Sstevel@tonic-gate * A cache line is composed of four quadwords with the associated ECC, the 10767c478bd9Sstevel@tonic-gate * MTag along with its associated ECC. This is depicted below: 10777c478bd9Sstevel@tonic-gate * 10787c478bd9Sstevel@tonic-gate * | Data | ECC | Mtag |MTag ECC| 10797c478bd9Sstevel@tonic-gate * 127 0 8 0 2 0 3 0 10807c478bd9Sstevel@tonic-gate * 10817c478bd9Sstevel@tonic-gate * synd_code will be mapped as the following order to mc_get_mem_unum. 10827c478bd9Sstevel@tonic-gate * 143 16 7 4 0 10837c478bd9Sstevel@tonic-gate * 10847c478bd9Sstevel@tonic-gate * | Quadword 0 | Quadword 1 | Quadword 2 | Quadword 3 | 10857c478bd9Sstevel@tonic-gate * 575 432 431 288 287 144 143 0 10867c478bd9Sstevel@tonic-gate * 10877c478bd9Sstevel@tonic-gate * dimm table: each bit at a cache line needs two bits to present one of 10887c478bd9Sstevel@tonic-gate * four dimms. So it needs 144 bytes(576 * 2 / 8). The content is in 10897c478bd9Sstevel@tonic-gate * big edian order, i.e. dimm_table[0] presents for bit 572 to 575. 10907c478bd9Sstevel@tonic-gate * 10917c478bd9Sstevel@tonic-gate * pin table: each bit at a cache line needs one byte to present pin position, 10927c478bd9Sstevel@tonic-gate * where max. is 230. So it needs 576 bytes. The order of table index is 10937c478bd9Sstevel@tonic-gate * the same as bit position at a cache line, i.e. pin_table[0] presents 10947c478bd9Sstevel@tonic-gate * for bit 0, Mtag ECC 0 of Quadword 3. 10957c478bd9Sstevel@tonic-gate * 10967c478bd9Sstevel@tonic-gate * This is a mapping from syndrome code to QuadWord Logical layout at Safari. 10977c478bd9Sstevel@tonic-gate * Referring to Figure 3-4, Excalibur Architecture Manual. 10987c478bd9Sstevel@tonic-gate * This table could be moved to cheetah.c if other platform teams agree with 10997c478bd9Sstevel@tonic-gate * the bit layout at QuadWord. 11007c478bd9Sstevel@tonic-gate */ 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate static uint8_t qwordmap[] = 11037c478bd9Sstevel@tonic-gate { 11047c478bd9Sstevel@tonic-gate 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 11057c478bd9Sstevel@tonic-gate 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 11067c478bd9Sstevel@tonic-gate 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 11077c478bd9Sstevel@tonic-gate 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 11087c478bd9Sstevel@tonic-gate 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 11097c478bd9Sstevel@tonic-gate 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 11107c478bd9Sstevel@tonic-gate 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 11117c478bd9Sstevel@tonic-gate 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 11127c478bd9Sstevel@tonic-gate 7, 8, 9, 10, 11, 12, 13, 14, 15, 4, 5, 6, 0, 1, 2, 3, 11137c478bd9Sstevel@tonic-gate }; 11147c478bd9Sstevel@tonic-gate 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate /* ARGSUSED */ 11177c478bd9Sstevel@tonic-gate static int 11187c478bd9Sstevel@tonic-gate mc_get_mem_unum(int synd_code, uint64_t paddr, char *buf, int buflen, int *lenp) 11197c478bd9Sstevel@tonic-gate { 11207c478bd9Sstevel@tonic-gate int i, upper_pa, lower_pa, dimmoffset; 11217c478bd9Sstevel@tonic-gate int quadword, pos_cacheline, position, index, idx4dimm; 11227c478bd9Sstevel@tonic-gate int qwlayout = synd_code; 11237c478bd9Sstevel@tonic-gate short offset, data; 11247c478bd9Sstevel@tonic-gate char unum[UNUM_NAMLEN]; 11257c478bd9Sstevel@tonic-gate struct dimm_info *dimmp; 11267c478bd9Sstevel@tonic-gate struct pin_info *pinp; 11277c478bd9Sstevel@tonic-gate struct bank_info *bank; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate /* 11307c478bd9Sstevel@tonic-gate * Enforce old Openboot requirement for synd code, either a single-bit 11317c478bd9Sstevel@tonic-gate * code from 0..QWORD_SIZE-1 or -1 (multi-bit error). 11327c478bd9Sstevel@tonic-gate */ 11337c478bd9Sstevel@tonic-gate if (qwlayout < -1 || qwlayout >= QWORD_SIZE) 11347c478bd9Sstevel@tonic-gate return (EINVAL); 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate unum[0] = '\0'; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate upper_pa = (paddr & MADR_UPA_MASK) >> MADR_UPA_SHIFT; 11397c478bd9Sstevel@tonic-gate lower_pa = (paddr & MADR_LPA_MASK) >> MADR_LPA_SHIFT; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate DPRINTF(MC_GUNUM_DEBUG, ("qwlayout %d\n", qwlayout)); 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate /* 11447c478bd9Sstevel@tonic-gate * Scan all logical banks to get one responding to the physical 11457c478bd9Sstevel@tonic-gate * address. Then compute the index to look up dimm and pin tables 1146*d00f0155Sayznaga * to generate the unum. 11477c478bd9Sstevel@tonic-gate */ 11487c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 11497c478bd9Sstevel@tonic-gate bank = (struct bank_info *)bank_head; 11507c478bd9Sstevel@tonic-gate while (bank != NULL) { 11517c478bd9Sstevel@tonic-gate int bankid, mcid, bankno_permc; 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate bankid = bank->bank_node.id; 11547c478bd9Sstevel@tonic-gate bankno_permc = bankid % NBANKS; 11557c478bd9Sstevel@tonic-gate mcid = bankid / NBANKS; 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate /* 11587c478bd9Sstevel@tonic-gate * The Address Decoding logic decodes the different fields 1159*d00f0155Sayznaga * in the Memory Address Decoding register to determine 1160*d00f0155Sayznaga * whether a particular logical bank should respond to a 11617c478bd9Sstevel@tonic-gate * physical address. 11627c478bd9Sstevel@tonic-gate */ 11637c478bd9Sstevel@tonic-gate if ((!bank->valid) || ((~(~(upper_pa ^ bank->um) | 11647c478bd9Sstevel@tonic-gate bank->uk)) || (~(~(lower_pa ^ bank->lm) | bank->lk)))) { 11657c478bd9Sstevel@tonic-gate bank = (struct bank_info *)bank->bank_node.next; 11667c478bd9Sstevel@tonic-gate continue; 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate dimmoffset = (bankno_permc % NDGRPS) * NDIMMS; 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate dimmp = (struct dimm_info *)bank->dimminfop; 11727c478bd9Sstevel@tonic-gate ASSERT(dimmp != NULL); 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate if ((qwlayout >= 0) && (qwlayout < QWORD_SIZE)) { 11757c478bd9Sstevel@tonic-gate /* 11767c478bd9Sstevel@tonic-gate * single-bit error handling, we can identify specific 11777c478bd9Sstevel@tonic-gate * DIMM. 11787c478bd9Sstevel@tonic-gate */ 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate pinp = (struct pin_info *)&dimmp->data[0]; 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate if (!dimmp->sym_flag) 11837c478bd9Sstevel@tonic-gate pinp++; 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate quadword = (paddr & 0x3f) / 16; 11867c478bd9Sstevel@tonic-gate /* or quadword = (paddr >> 4) % 4; */ 1187*d00f0155Sayznaga pos_cacheline = ((3 - quadword) * QWORD_SIZE) + 11887c478bd9Sstevel@tonic-gate qwordmap[qwlayout]; 11897c478bd9Sstevel@tonic-gate position = 575 - pos_cacheline; 11907c478bd9Sstevel@tonic-gate index = position * 2 / 8; 11917c478bd9Sstevel@tonic-gate offset = position % 4; 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate /* 1194*d00f0155Sayznaga * Trade-off: We couldn't add pin number to 1195*d00f0155Sayznaga * unum string because statistic number 11967c478bd9Sstevel@tonic-gate * pumps up at the corresponding dimm not pin. 11977c478bd9Sstevel@tonic-gate * (void) sprintf(unum, "Pin %1u ", (uint_t) 11987c478bd9Sstevel@tonic-gate * pinp->pintable[pos_cacheline]); 11997c478bd9Sstevel@tonic-gate */ 12007c478bd9Sstevel@tonic-gate DPRINTF(MC_GUNUM_DEBUG, ("Pin number %1u\n", 12017c478bd9Sstevel@tonic-gate (uint_t)pinp->pintable[pos_cacheline])); 12027c478bd9Sstevel@tonic-gate data = pinp->dimmtable[index]; 12037c478bd9Sstevel@tonic-gate idx4dimm = (data >> ((3 - offset) * 2)) & 3; 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate (void) strncpy(unum, 12067c478bd9Sstevel@tonic-gate (char *)dimmp->label[dimmoffset + idx4dimm], 12077c478bd9Sstevel@tonic-gate UNUM_NAMLEN); 12087c478bd9Sstevel@tonic-gate DPRINTF(MC_GUNUM_DEBUG, ("unum %s\n", unum)); 12097c478bd9Sstevel@tonic-gate /* 12107c478bd9Sstevel@tonic-gate * platform hook for adding label information to unum. 12117c478bd9Sstevel@tonic-gate */ 12127c478bd9Sstevel@tonic-gate mc_add_mem_unum_label(unum, mcid, bankno_permc, 12137c478bd9Sstevel@tonic-gate idx4dimm); 12147c478bd9Sstevel@tonic-gate } else { 12157c478bd9Sstevel@tonic-gate char *p = unum; 12167c478bd9Sstevel@tonic-gate size_t res = UNUM_NAMLEN; 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate /* 12197c478bd9Sstevel@tonic-gate * multi-bit error handling, we can only identify 12207c478bd9Sstevel@tonic-gate * bank of DIMMs. 12217c478bd9Sstevel@tonic-gate */ 12227c478bd9Sstevel@tonic-gate 12237c478bd9Sstevel@tonic-gate for (i = 0; (i < NDIMMS) && (res > 0); i++) { 12247c478bd9Sstevel@tonic-gate (void) snprintf(p, res, "%s%s", 12257c478bd9Sstevel@tonic-gate i == 0 ? "" : " ", 12267c478bd9Sstevel@tonic-gate (char *)dimmp->label[dimmoffset + i]); 12277c478bd9Sstevel@tonic-gate res -= strlen(p); 12287c478bd9Sstevel@tonic-gate p += strlen(p); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /* 12327c478bd9Sstevel@tonic-gate * platform hook for adding label information 12337c478bd9Sstevel@tonic-gate * to unum. 12347c478bd9Sstevel@tonic-gate */ 12357c478bd9Sstevel@tonic-gate mc_add_mem_unum_label(unum, mcid, bankno_permc, -1); 12367c478bd9Sstevel@tonic-gate } 12377c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 12387c478bd9Sstevel@tonic-gate if ((strlen(unum) >= UNUM_NAMLEN) || 12397c478bd9Sstevel@tonic-gate (strlen(unum) >= buflen)) { 12407c478bd9Sstevel@tonic-gate return (ENOSPC); 12417c478bd9Sstevel@tonic-gate } else { 12427c478bd9Sstevel@tonic-gate (void) strncpy(buf, unum, buflen); 12437c478bd9Sstevel@tonic-gate *lenp = strlen(buf); 12447c478bd9Sstevel@tonic-gate return (0); 12457c478bd9Sstevel@tonic-gate } 1246*d00f0155Sayznaga } /* end of while loop for logical bank list */ 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 12497c478bd9Sstevel@tonic-gate return (ENXIO); 12507c478bd9Sstevel@tonic-gate } 12517c478bd9Sstevel@tonic-gate 1252*d00f0155Sayznaga /* ARGSUSED */ 1253*d00f0155Sayznaga static int 1254*d00f0155Sayznaga mc_get_mem_offset(uint64_t paddr, uint64_t *offp) 1255*d00f0155Sayznaga { 1256*d00f0155Sayznaga int upper_pa, lower_pa; 1257*d00f0155Sayznaga struct bank_info *bank; 1258*d00f0155Sayznaga struct seg_info *seg; 1259*d00f0155Sayznaga 1260*d00f0155Sayznaga upper_pa = (paddr & MADR_UPA_MASK) >> MADR_UPA_SHIFT; 1261*d00f0155Sayznaga lower_pa = (paddr & MADR_LPA_MASK) >> MADR_LPA_SHIFT; 1262*d00f0155Sayznaga 1263*d00f0155Sayznaga /* 1264*d00f0155Sayznaga * Scan all logical banks to get one responding to the physical 1265*d00f0155Sayznaga * address. 1266*d00f0155Sayznaga */ 1267*d00f0155Sayznaga mutex_enter(&mcdatamutex); 1268*d00f0155Sayznaga bank = (struct bank_info *)bank_head; 1269*d00f0155Sayznaga while (bank != NULL) { 1270*d00f0155Sayznaga /* 1271*d00f0155Sayznaga * The Address Decoding logic decodes the different fields 1272*d00f0155Sayznaga * in the Memory Address Decoding register to determine 1273*d00f0155Sayznaga * whether a particular logical bank should respond to a 1274*d00f0155Sayznaga * physical address. 1275*d00f0155Sayznaga */ 1276*d00f0155Sayznaga if ((!bank->valid) || ((~(~(upper_pa ^ bank->um) | 1277*d00f0155Sayznaga bank->uk)) || (~(~(lower_pa ^ bank->lm) | bank->lk)))) { 1278*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 1279*d00f0155Sayznaga continue; 1280*d00f0155Sayznaga } 1281*d00f0155Sayznaga 1282*d00f0155Sayznaga seg = (struct seg_info *)mc_node_get(bank->seg_id, seg_head); 1283*d00f0155Sayznaga ASSERT(seg != NULL); 1284*d00f0155Sayznaga ASSERT(paddr >= seg->base); 1285*d00f0155Sayznaga 1286*d00f0155Sayznaga mc_addr_to_offset(seg, bank, paddr, offp); 1287*d00f0155Sayznaga 1288*d00f0155Sayznaga mutex_exit(&mcdatamutex); 1289*d00f0155Sayznaga return (0); 1290*d00f0155Sayznaga } 1291*d00f0155Sayznaga 1292*d00f0155Sayznaga mutex_exit(&mcdatamutex); 1293*d00f0155Sayznaga return (ENXIO); 1294*d00f0155Sayznaga } 1295*d00f0155Sayznaga 1296*d00f0155Sayznaga /* 1297*d00f0155Sayznaga * Translate a DIMM <id, offset> pair to a physical address. 1298*d00f0155Sayznaga */ 1299*d00f0155Sayznaga static int 1300*d00f0155Sayznaga mc_get_mem_addr(int mcid, char *sid, uint64_t off, uint64_t *paddr) 1301*d00f0155Sayznaga { 1302*d00f0155Sayznaga struct seg_info *seg; 1303*d00f0155Sayznaga struct bank_info *bank; 1304*d00f0155Sayznaga int first_seg_id; 1305*d00f0155Sayznaga int i, found; 1306*d00f0155Sayznaga 1307*d00f0155Sayznaga ASSERT(sid != NULL); 1308*d00f0155Sayznaga 1309*d00f0155Sayznaga mutex_enter(&mcdatamutex); 1310*d00f0155Sayznaga 1311*d00f0155Sayznaga rw_enter(&mcdimmsids_rw, RW_READER); 1312*d00f0155Sayznaga 1313*d00f0155Sayznaga /* 1314*d00f0155Sayznaga * If DIMM serial ids have not been cached yet, tell the 1315*d00f0155Sayznaga * caller to try again. 1316*d00f0155Sayznaga */ 1317*d00f0155Sayznaga if (mc_dimm_sids == NULL) { 1318*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 1319*d00f0155Sayznaga return (EAGAIN); 1320*d00f0155Sayznaga } 1321*d00f0155Sayznaga 1322*d00f0155Sayznaga for (i = 0; i < max_entries; i++) { 1323*d00f0155Sayznaga if (mc_dimm_sids[i].mcid == mcid) 1324*d00f0155Sayznaga break; 1325*d00f0155Sayznaga } 1326*d00f0155Sayznaga 1327*d00f0155Sayznaga if (i == max_entries) { 1328*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 1329*d00f0155Sayznaga mutex_exit(&mcdatamutex); 1330*d00f0155Sayznaga return (ENODEV); 1331*d00f0155Sayznaga } 1332*d00f0155Sayznaga 1333*d00f0155Sayznaga first_seg_id = mc_dimm_sids[i].seg_id; 1334*d00f0155Sayznaga 1335*d00f0155Sayznaga seg = (struct seg_info *)mc_node_get(first_seg_id, seg_head); 1336*d00f0155Sayznaga 1337*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 1338*d00f0155Sayznaga 1339*d00f0155Sayznaga if (seg == NULL) { 1340*d00f0155Sayznaga mutex_exit(&mcdatamutex); 1341*d00f0155Sayznaga return (ENODEV); 1342*d00f0155Sayznaga } 1343*d00f0155Sayznaga 1344*d00f0155Sayznaga found = 0; 1345*d00f0155Sayznaga 1346*d00f0155Sayznaga for (bank = seg->hb_inseg; bank; bank = bank->n_inseg) { 1347*d00f0155Sayznaga ASSERT(bank->valid); 1348*d00f0155Sayznaga 1349*d00f0155Sayznaga for (i = 0; i < NDIMMS; i++) { 1350*d00f0155Sayznaga if (strncmp((char *)bank->dimmsidp[i], sid, 1351*d00f0155Sayznaga DIMM_SERIAL_ID_LEN) == 0) 1352*d00f0155Sayznaga break; 1353*d00f0155Sayznaga } 1354*d00f0155Sayznaga 1355*d00f0155Sayznaga if (i == NDIMMS) 1356*d00f0155Sayznaga continue; 1357*d00f0155Sayznaga 1358*d00f0155Sayznaga if (mc_offset_to_addr(seg, bank, off, paddr) == -1) 1359*d00f0155Sayznaga continue; 1360*d00f0155Sayznaga found = 1; 1361*d00f0155Sayznaga break; 1362*d00f0155Sayznaga } 1363*d00f0155Sayznaga 1364*d00f0155Sayznaga if (found) { 1365*d00f0155Sayznaga mutex_exit(&mcdatamutex); 1366*d00f0155Sayznaga return (0); 1367*d00f0155Sayznaga } 1368*d00f0155Sayznaga 1369*d00f0155Sayznaga /* 1370*d00f0155Sayznaga * If a bank wasn't found, it may be in another segment. 1371*d00f0155Sayznaga * This can happen if the different logical banks of an MC 1372*d00f0155Sayznaga * have different interleave factors. To deal with this 1373*d00f0155Sayznaga * possibility, we'll do a brute-force search for banks 1374*d00f0155Sayznaga * for this MC with a different seg id then above. 1375*d00f0155Sayznaga */ 1376*d00f0155Sayznaga bank = (struct bank_info *)bank_head; 1377*d00f0155Sayznaga while (bank != NULL) { 1378*d00f0155Sayznaga 1379*d00f0155Sayznaga if (!bank->valid) { 1380*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 1381*d00f0155Sayznaga continue; 1382*d00f0155Sayznaga } 1383*d00f0155Sayznaga 1384*d00f0155Sayznaga if (bank->bank_node.id / NBANKS != mcid) { 1385*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 1386*d00f0155Sayznaga continue; 1387*d00f0155Sayznaga } 1388*d00f0155Sayznaga 1389*d00f0155Sayznaga /* Ignore banks in the segment we looked in above. */ 1390*d00f0155Sayznaga if (bank->seg_id == mc_dimm_sids[i].seg_id) { 1391*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 1392*d00f0155Sayznaga continue; 1393*d00f0155Sayznaga } 1394*d00f0155Sayznaga 1395*d00f0155Sayznaga for (i = 0; i < NDIMMS; i++) { 1396*d00f0155Sayznaga if (strncmp((char *)bank->dimmsidp[i], sid, 1397*d00f0155Sayznaga DIMM_SERIAL_ID_LEN) == 0) 1398*d00f0155Sayznaga break; 1399*d00f0155Sayznaga } 1400*d00f0155Sayznaga 1401*d00f0155Sayznaga if (i == NDIMMS) { 1402*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 1403*d00f0155Sayznaga continue; 1404*d00f0155Sayznaga } 1405*d00f0155Sayznaga 1406*d00f0155Sayznaga seg = (struct seg_info *)mc_node_get(bank->seg_id, seg_head); 1407*d00f0155Sayznaga 1408*d00f0155Sayznaga if (mc_offset_to_addr(seg, bank, off, paddr) == -1) { 1409*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 1410*d00f0155Sayznaga continue; 1411*d00f0155Sayznaga } 1412*d00f0155Sayznaga 1413*d00f0155Sayznaga found = 1; 1414*d00f0155Sayznaga break; 1415*d00f0155Sayznaga } 1416*d00f0155Sayznaga 1417*d00f0155Sayznaga mutex_exit(&mcdatamutex); 1418*d00f0155Sayznaga 1419*d00f0155Sayznaga if (found) 1420*d00f0155Sayznaga return (0); 1421*d00f0155Sayznaga else 1422*d00f0155Sayznaga return (ENOENT); 1423*d00f0155Sayznaga } 1424*d00f0155Sayznaga 14257c478bd9Sstevel@tonic-gate static int 14267c478bd9Sstevel@tonic-gate mc_get_mem_info(int synd_code, uint64_t paddr, 14277c478bd9Sstevel@tonic-gate uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep, 14287c478bd9Sstevel@tonic-gate int *segsp, int *banksp, int *mcidp) 14297c478bd9Sstevel@tonic-gate { 14307c478bd9Sstevel@tonic-gate int upper_pa, lower_pa; 14317c478bd9Sstevel@tonic-gate struct bank_info *bankp; 14327c478bd9Sstevel@tonic-gate 14337c478bd9Sstevel@tonic-gate if (synd_code < -1 || synd_code >= QWORD_SIZE) 14347c478bd9Sstevel@tonic-gate return (EINVAL); 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate upper_pa = (paddr & MADR_UPA_MASK) >> MADR_UPA_SHIFT; 14377c478bd9Sstevel@tonic-gate lower_pa = (paddr & MADR_LPA_MASK) >> MADR_LPA_SHIFT; 14387c478bd9Sstevel@tonic-gate 14397c478bd9Sstevel@tonic-gate /* 14407c478bd9Sstevel@tonic-gate * Scan all logical banks to get one responding to the physical 14417c478bd9Sstevel@tonic-gate * address. 14427c478bd9Sstevel@tonic-gate */ 14437c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 14447c478bd9Sstevel@tonic-gate bankp = (struct bank_info *)bank_head; 14457c478bd9Sstevel@tonic-gate while (bankp != NULL) { 14467c478bd9Sstevel@tonic-gate struct seg_info *segp; 14477c478bd9Sstevel@tonic-gate int bankid, mcid; 14487c478bd9Sstevel@tonic-gate 14497c478bd9Sstevel@tonic-gate bankid = bankp->bank_node.id; 14507c478bd9Sstevel@tonic-gate mcid = bankid / NBANKS; 14517c478bd9Sstevel@tonic-gate 14527c478bd9Sstevel@tonic-gate /* 14537c478bd9Sstevel@tonic-gate * The Address Decoding logic decodes the different fields 14547c478bd9Sstevel@tonic-gate * in the Memory Address Decoding register to determine 1455*d00f0155Sayznaga * whether a particular logical bank should respond to a 14567c478bd9Sstevel@tonic-gate * physical address. 14577c478bd9Sstevel@tonic-gate */ 14587c478bd9Sstevel@tonic-gate if ((!bankp->valid) || ((~(~(upper_pa ^ bankp->um) | 14597c478bd9Sstevel@tonic-gate bankp->uk)) || (~(~(lower_pa ^ bankp->lm) | bankp->lk)))) { 14607c478bd9Sstevel@tonic-gate bankp = (struct bank_info *)bankp->bank_node.next; 14617c478bd9Sstevel@tonic-gate continue; 14627c478bd9Sstevel@tonic-gate } 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate /* 14657c478bd9Sstevel@tonic-gate * Get the corresponding segment. 14667c478bd9Sstevel@tonic-gate */ 14677c478bd9Sstevel@tonic-gate if ((segp = (struct seg_info *)mc_node_get(bankp->seg_id, 14687c478bd9Sstevel@tonic-gate seg_head)) == NULL) { 14697c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 14707c478bd9Sstevel@tonic-gate return (EFAULT); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate 14737c478bd9Sstevel@tonic-gate *mem_sizep = memsize; 14747c478bd9Sstevel@tonic-gate *seg_sizep = segp->size; 14757c478bd9Sstevel@tonic-gate *bank_sizep = bankp->size; 14767c478bd9Sstevel@tonic-gate *segsp = nsegments; 14777c478bd9Sstevel@tonic-gate *banksp = segp->nbanks; 14787c478bd9Sstevel@tonic-gate *mcidp = mcid; 14797c478bd9Sstevel@tonic-gate 14807c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 14817c478bd9Sstevel@tonic-gate 14827c478bd9Sstevel@tonic-gate return (0); 14837c478bd9Sstevel@tonic-gate 1484*d00f0155Sayznaga } /* end of while loop for logical bank list */ 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 14877c478bd9Sstevel@tonic-gate return (ENXIO); 14887c478bd9Sstevel@tonic-gate } 14897c478bd9Sstevel@tonic-gate 14907c478bd9Sstevel@tonic-gate /* 14917c478bd9Sstevel@tonic-gate * Construct lists for an enabled MC where size of memory is 0. 14927c478bd9Sstevel@tonic-gate * The lists are connected as follows: 14937c478bd9Sstevel@tonic-gate * Attached MC -> device group list -> device list(per devgrp). 14947c478bd9Sstevel@tonic-gate */ 14957c478bd9Sstevel@tonic-gate static void 14967c478bd9Sstevel@tonic-gate mc_construct(int mc_id, void *dimminfop) 14977c478bd9Sstevel@tonic-gate { 14987c478bd9Sstevel@tonic-gate int i, j, idx, dmidx; 14997c478bd9Sstevel@tonic-gate struct mctrl_info *mctrl; 15007c478bd9Sstevel@tonic-gate struct dgrp_info *dgrp; 15017c478bd9Sstevel@tonic-gate struct device_info *dev; 15027c478bd9Sstevel@tonic-gate struct dimm_info *dimmp = (struct dimm_info *)dimminfop; 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 15057c478bd9Sstevel@tonic-gate /* allocate for mctrl_info and bank_info */ 15067c478bd9Sstevel@tonic-gate if ((mctrl = (struct mctrl_info *)mc_node_get(mc_id, 15077c478bd9Sstevel@tonic-gate mctrl_head)) != NULL) { 15087c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mc_construct: mctrl %d exists\n", mc_id); 15097c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 15107c478bd9Sstevel@tonic-gate return; 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate 15137c478bd9Sstevel@tonic-gate mctrl = kmem_zalloc(sizeof (struct mctrl_info), KM_SLEEP); 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate /* 15167c478bd9Sstevel@tonic-gate * If dimminfop is NULL, the Memory Controller is disable, and 15177c478bd9Sstevel@tonic-gate * the number of device group will be zero. 15187c478bd9Sstevel@tonic-gate */ 15197c478bd9Sstevel@tonic-gate if (dimminfop == NULL) { 15207c478bd9Sstevel@tonic-gate mctrl->mctrl_node.id = mc_id; 15217c478bd9Sstevel@tonic-gate mctrl->ndevgrps = 0; 15227c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail); 15237c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 15247c478bd9Sstevel@tonic-gate return; 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate /* add the entry on dgrp_info list */ 15287c478bd9Sstevel@tonic-gate for (i = 0; i < NDGRPS; i++) { 15297c478bd9Sstevel@tonic-gate idx = mc_id * NDGRPS + i; 15307c478bd9Sstevel@tonic-gate mctrl->devgrpids[i] = idx; 15317c478bd9Sstevel@tonic-gate if ((dgrp = (struct dgrp_info *)mc_node_get(idx, dgrp_head)) 15327c478bd9Sstevel@tonic-gate != NULL) { 15337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mc_construct: devgrp %d exists\n", 15347c478bd9Sstevel@tonic-gate idx); 15357c478bd9Sstevel@tonic-gate continue; 15367c478bd9Sstevel@tonic-gate } 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate dgrp = kmem_zalloc(sizeof (struct dgrp_info), KM_SLEEP); 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* add the entry on device_info list */ 15417c478bd9Sstevel@tonic-gate for (j = 0; j < NDIMMS; j++) { 15427c478bd9Sstevel@tonic-gate dmidx = idx * NDIMMS + j; 15437c478bd9Sstevel@tonic-gate dgrp->deviceids[j] = dmidx; 15447c478bd9Sstevel@tonic-gate if ((dev = (struct device_info *) 15457c478bd9Sstevel@tonic-gate mc_node_get(dmidx, device_head)) != NULL) { 15467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mc_construct: device %d " 15477c478bd9Sstevel@tonic-gate "exists\n", dmidx); 15487c478bd9Sstevel@tonic-gate continue; 15497c478bd9Sstevel@tonic-gate } 15507c478bd9Sstevel@tonic-gate dev = kmem_zalloc(sizeof (struct device_info), 15517c478bd9Sstevel@tonic-gate KM_SLEEP); 15527c478bd9Sstevel@tonic-gate dev->dev_node.id = dmidx; 15537c478bd9Sstevel@tonic-gate dev->size = 0; 15547c478bd9Sstevel@tonic-gate (void) strncpy(dev->label, (char *) 15557c478bd9Sstevel@tonic-gate dimmp->label[i * NDIMMS + j], MAX_DEVLEN); 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)dev, &device_head, 15587c478bd9Sstevel@tonic-gate &device_tail); 15597c478bd9Sstevel@tonic-gate } /* for loop for constructing device_info */ 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate dgrp->dgrp_node.id = idx; 15627c478bd9Sstevel@tonic-gate dgrp->ndevices = NDIMMS; 15637c478bd9Sstevel@tonic-gate dgrp->size = 0; 15647c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)dgrp, &dgrp_head, &dgrp_tail); 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate } /* end of for loop for constructing dgrp_info list */ 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate mctrl->mctrl_node.id = mc_id; 15697c478bd9Sstevel@tonic-gate mctrl->ndevgrps = NDGRPS; 15707c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail); 15717c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 15727c478bd9Sstevel@tonic-gate } 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * Construct lists for Memory Configuration at logical viewpoint. 15767c478bd9Sstevel@tonic-gate * 15777c478bd9Sstevel@tonic-gate * Retrieve information from Memory Address Decoding Register and set up 15787c478bd9Sstevel@tonic-gate * bank and segment lists. Link bank to its corresponding device group, and 15797c478bd9Sstevel@tonic-gate * update size of device group and devices. Also connect bank to the segment. 15807c478bd9Sstevel@tonic-gate * 15817c478bd9Sstevel@tonic-gate * Memory Address Decoding Register 15827c478bd9Sstevel@tonic-gate * ------------------------------------------------------------------------- 15837c478bd9Sstevel@tonic-gate * |63|62 53|52 41|40 37|36 20|19 18|17 14|13 12|11 8|7 0| 15847c478bd9Sstevel@tonic-gate * |-----------|----------|------|---------|-----|------|-----|-----|-------| 15857c478bd9Sstevel@tonic-gate * |V | - | UK | - | UM | - | LK | - | LM | - | 15867c478bd9Sstevel@tonic-gate * ------------------------------------------------------------------------- 15877c478bd9Sstevel@tonic-gate * 15887c478bd9Sstevel@tonic-gate */ 15897c478bd9Sstevel@tonic-gate 15907c478bd9Sstevel@tonic-gate static int 15917c478bd9Sstevel@tonic-gate mlayout_add(int mc_id, int bank_no, uint64_t reg, void *dimminfop) 15927c478bd9Sstevel@tonic-gate { 15937c478bd9Sstevel@tonic-gate int i, dmidx, idx; 15947c478bd9Sstevel@tonic-gate uint32_t ifactor; 15957c478bd9Sstevel@tonic-gate int status = 0; 15967c478bd9Sstevel@tonic-gate uint64_t size, base; 15977c478bd9Sstevel@tonic-gate struct seg_info *seg_curr; 15987c478bd9Sstevel@tonic-gate struct bank_info *bank_curr; 15997c478bd9Sstevel@tonic-gate struct dgrp_info *dgrp; 16007c478bd9Sstevel@tonic-gate struct device_info *dev; 16017c478bd9Sstevel@tonic-gate union { 16027c478bd9Sstevel@tonic-gate struct { 16037c478bd9Sstevel@tonic-gate uint64_t valid : 1; 16047c478bd9Sstevel@tonic-gate uint64_t resrv1 : 10; 16057c478bd9Sstevel@tonic-gate uint64_t uk : 12; 16067c478bd9Sstevel@tonic-gate uint64_t resrv2 : 4; 16077c478bd9Sstevel@tonic-gate uint64_t um : 17; 16087c478bd9Sstevel@tonic-gate uint64_t resrv3 : 2; 16097c478bd9Sstevel@tonic-gate uint64_t lk : 4; 16107c478bd9Sstevel@tonic-gate uint64_t resrv4 : 2; 16117c478bd9Sstevel@tonic-gate uint64_t lm : 4; 16127c478bd9Sstevel@tonic-gate uint64_t resrv5 : 8; 16137c478bd9Sstevel@tonic-gate } _s; 16147c478bd9Sstevel@tonic-gate uint64_t madreg; 16157c478bd9Sstevel@tonic-gate } mcreg; 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate mcreg.madreg = reg; 16187c478bd9Sstevel@tonic-gate 16197c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mlayout_add: mc_id %d, bank num " 1620f47a9c50Smathue "%d, reg 0x%lx\n", mc_id, bank_no, reg)); 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate /* add the entry on bank_info list */ 16237c478bd9Sstevel@tonic-gate idx = mc_id * NBANKS + bank_no; 16247c478bd9Sstevel@tonic-gate 16257c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 16267c478bd9Sstevel@tonic-gate if ((bank_curr = (struct bank_info *)mc_node_get(idx, bank_head)) 16277c478bd9Sstevel@tonic-gate != NULL) { 16287c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mlayout_add: bank %d exists\n", bank_no); 16297c478bd9Sstevel@tonic-gate goto exit; 16307c478bd9Sstevel@tonic-gate } 16317c478bd9Sstevel@tonic-gate 16327c478bd9Sstevel@tonic-gate bank_curr = kmem_zalloc(sizeof (struct bank_info), KM_SLEEP); 16337c478bd9Sstevel@tonic-gate bank_curr->bank_node.id = idx; 16347c478bd9Sstevel@tonic-gate bank_curr->valid = mcreg._s.valid; 16357c478bd9Sstevel@tonic-gate bank_curr->dimminfop = dimminfop; 16367c478bd9Sstevel@tonic-gate 16377c478bd9Sstevel@tonic-gate if (!mcreg._s.valid) { 16387c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)bank_curr, &bank_head, &bank_tail); 16397c478bd9Sstevel@tonic-gate goto exit; 16407c478bd9Sstevel@tonic-gate } 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate /* 16437c478bd9Sstevel@tonic-gate * size of a logical bank = size of segment / interleave factor 16447c478bd9Sstevel@tonic-gate * This fomula is not only working for regular configuration, 16457c478bd9Sstevel@tonic-gate * i.e. number of banks at a segment equals to the max 16467c478bd9Sstevel@tonic-gate * interleave factor, but also for special case, say 3 bank 16477c478bd9Sstevel@tonic-gate * interleave. One bank is 2 way interleave and other two are 16487c478bd9Sstevel@tonic-gate * 4 way. So the sizes of banks are size of segment/2 and /4 16497c478bd9Sstevel@tonic-gate * respectively. 16507c478bd9Sstevel@tonic-gate */ 16517c478bd9Sstevel@tonic-gate ifactor = (mcreg._s.lk ^ 0xF) + 1; 16527c478bd9Sstevel@tonic-gate size = (((mcreg._s.uk & 0x3FF) + 1) * 0x4000000) / ifactor; 16537c478bd9Sstevel@tonic-gate base = mcreg._s.um & ~mcreg._s.uk; 16547c478bd9Sstevel@tonic-gate base <<= MADR_UPA_SHIFT; 16557c478bd9Sstevel@tonic-gate 16567c478bd9Sstevel@tonic-gate bank_curr->uk = mcreg._s.uk; 16577c478bd9Sstevel@tonic-gate bank_curr->um = mcreg._s.um; 16587c478bd9Sstevel@tonic-gate bank_curr->lk = mcreg._s.lk; 16597c478bd9Sstevel@tonic-gate bank_curr->lm = mcreg._s.lm; 16607c478bd9Sstevel@tonic-gate bank_curr->size = size; 16617c478bd9Sstevel@tonic-gate 1662*d00f0155Sayznaga /* 1663*d00f0155Sayznaga * The bank's position depends on which halves of the DIMMs it consists 1664*d00f0155Sayznaga * of. The front-side halves of the 4 DIMMs constitute the front bank 1665*d00f0155Sayznaga * and the back-side halves constitute the back bank. Bank numbers 1666*d00f0155Sayznaga * 0 and 1 are front-side banks and bank numbers 2 and 3 are back side 1667*d00f0155Sayznaga * banks. 1668*d00f0155Sayznaga */ 1669*d00f0155Sayznaga bank_curr->pos = bank_no >> 1; 1670*d00f0155Sayznaga ASSERT((bank_curr->pos == 0) || (bank_curr->pos == 1)); 1671*d00f0155Sayznaga 16727c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mlayout_add 3: logical bank num %d, " 1673f47a9c50Smathue "lk 0x%x uk 0x%x um 0x%x ifactor 0x%x size 0x%lx base 0x%lx\n", 1674f47a9c50Smathue idx, mcreg._s.lk, mcreg._s.uk, mcreg._s.um, ifactor, size, base)); 16757c478bd9Sstevel@tonic-gate 16767c478bd9Sstevel@tonic-gate /* connect the entry and update the size on dgrp_info list */ 16777c478bd9Sstevel@tonic-gate idx = mc_id * NDGRPS + (bank_no % NDGRPS); 16787c478bd9Sstevel@tonic-gate if ((dgrp = (struct dgrp_info *)mc_node_get(idx, dgrp_head)) == NULL) { 16797c478bd9Sstevel@tonic-gate /* all avaiable dgrp should be linked at mc_construct */ 16807c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mlayout_add: dgrp %d doesn't exist\n", idx); 16817c478bd9Sstevel@tonic-gate kmem_free(bank_curr, sizeof (struct bank_info)); 16827c478bd9Sstevel@tonic-gate status = -1; 16837c478bd9Sstevel@tonic-gate goto exit; 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate bank_curr->devgrp_id = idx; 16877c478bd9Sstevel@tonic-gate dgrp->size += size; 16887c478bd9Sstevel@tonic-gate 16897c478bd9Sstevel@tonic-gate /* Update the size of entry on device_info list */ 16907c478bd9Sstevel@tonic-gate for (i = 0; i < NDIMMS; i++) { 16917c478bd9Sstevel@tonic-gate dmidx = dgrp->dgrp_node.id * NDIMMS + i; 16927c478bd9Sstevel@tonic-gate dgrp->deviceids[i] = dmidx; 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate /* avaiable device should be linked at mc_construct */ 16957c478bd9Sstevel@tonic-gate if ((dev = (struct device_info *)mc_node_get(dmidx, 16967c478bd9Sstevel@tonic-gate device_head)) == NULL) { 16977c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mlayout_add:dev %d doesn't exist\n", 16987c478bd9Sstevel@tonic-gate dmidx); 16997c478bd9Sstevel@tonic-gate kmem_free(bank_curr, sizeof (struct bank_info)); 17007c478bd9Sstevel@tonic-gate status = -1; 17017c478bd9Sstevel@tonic-gate goto exit; 17027c478bd9Sstevel@tonic-gate } 17037c478bd9Sstevel@tonic-gate 17047c478bd9Sstevel@tonic-gate dev->size += (size / NDIMMS); 17057c478bd9Sstevel@tonic-gate 1706f47a9c50Smathue DPRINTF(MC_CNSTRC_DEBUG, ("mlayout_add DIMM:id %d, size %lu\n", 17077c478bd9Sstevel@tonic-gate dmidx, size)); 17087c478bd9Sstevel@tonic-gate } 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate /* 17117c478bd9Sstevel@tonic-gate * Get the segment by matching the base address, link this bank 17127c478bd9Sstevel@tonic-gate * to the segment. If not matched, allocate a new segment and 17137c478bd9Sstevel@tonic-gate * add it at segment list. 17147c478bd9Sstevel@tonic-gate */ 17157c478bd9Sstevel@tonic-gate if (seg_curr = seg_match_base(base)) { 17167c478bd9Sstevel@tonic-gate seg_curr->nbanks++; 17177c478bd9Sstevel@tonic-gate seg_curr->size += size; 17187c478bd9Sstevel@tonic-gate if (ifactor > seg_curr->ifactor) 17197c478bd9Sstevel@tonic-gate seg_curr->ifactor = ifactor; 17207c478bd9Sstevel@tonic-gate bank_curr->seg_id = seg_curr->seg_node.id; 17217c478bd9Sstevel@tonic-gate } else { 17227c478bd9Sstevel@tonic-gate seg_curr = (struct seg_info *) 17237c478bd9Sstevel@tonic-gate kmem_zalloc(sizeof (struct seg_info), KM_SLEEP); 17247c478bd9Sstevel@tonic-gate bank_curr->seg_id = seg_id; 17257c478bd9Sstevel@tonic-gate seg_curr->seg_node.id = seg_id++; 17267c478bd9Sstevel@tonic-gate seg_curr->base = base; 17277c478bd9Sstevel@tonic-gate seg_curr->size = size; 17287c478bd9Sstevel@tonic-gate seg_curr->nbanks = 1; 17297c478bd9Sstevel@tonic-gate seg_curr->ifactor = ifactor; 17307c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)seg_curr, &seg_head, &seg_tail); 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate nsegments++; 17337c478bd9Sstevel@tonic-gate } 17347c478bd9Sstevel@tonic-gate 17357c478bd9Sstevel@tonic-gate /* Get the local id of bank which is only unique per segment. */ 17367c478bd9Sstevel@tonic-gate bank_curr->local_id = seg_curr->nbanks - 1; 17377c478bd9Sstevel@tonic-gate 17387c478bd9Sstevel@tonic-gate /* add bank at the end of the list; not sorted by bankid */ 17397c478bd9Sstevel@tonic-gate if (seg_curr->hb_inseg != NULL) { 17407c478bd9Sstevel@tonic-gate bank_curr->p_inseg = seg_curr->tb_inseg; 17417c478bd9Sstevel@tonic-gate bank_curr->n_inseg = seg_curr->tb_inseg->n_inseg; 17427c478bd9Sstevel@tonic-gate seg_curr->tb_inseg->n_inseg = bank_curr; 17437c478bd9Sstevel@tonic-gate seg_curr->tb_inseg = bank_curr; 17447c478bd9Sstevel@tonic-gate } else { 17457c478bd9Sstevel@tonic-gate bank_curr->n_inseg = bank_curr->p_inseg = NULL; 17467c478bd9Sstevel@tonic-gate seg_curr->hb_inseg = seg_curr->tb_inseg = bank_curr; 17477c478bd9Sstevel@tonic-gate } 17487c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mlayout_add: + bank to seg, id %d\n", 17497c478bd9Sstevel@tonic-gate seg_curr->seg_node.id)); 17507c478bd9Sstevel@tonic-gate 17517c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)bank_curr, &bank_head, &bank_tail); 17527c478bd9Sstevel@tonic-gate 17537c478bd9Sstevel@tonic-gate memsize += size; 17547c478bd9Sstevel@tonic-gate if (seg_curr->nbanks > maxbanks) 17557c478bd9Sstevel@tonic-gate maxbanks = seg_curr->nbanks; 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate exit: 17587c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 17597c478bd9Sstevel@tonic-gate return (status); 17607c478bd9Sstevel@tonic-gate } 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate /* 17637c478bd9Sstevel@tonic-gate * Delete nodes related to the given MC on mc, device group, device, 17647c478bd9Sstevel@tonic-gate * and bank lists. Moreover, delete corresponding segment if its connected 17657c478bd9Sstevel@tonic-gate * banks are all removed. 1766*d00f0155Sayznaga * 1767*d00f0155Sayznaga * The "delete" argument is 1 if this is called as a result of DDI_DETACH. In 1768*d00f0155Sayznaga * this case, the DIMM data structures need to be deleted. The argument is 1769*d00f0155Sayznaga * 0 if this called as a result of DDI_SUSPEND/DDI_RESUME. In this case, 1770*d00f0155Sayznaga * the DIMM data structures are left alone. 17717c478bd9Sstevel@tonic-gate */ 17727c478bd9Sstevel@tonic-gate static void 1773*d00f0155Sayznaga mlayout_del(int mc_id, int delete) 17747c478bd9Sstevel@tonic-gate { 17757c478bd9Sstevel@tonic-gate int i, j, dgrpid, devid, bankid, ndevgrps; 17767c478bd9Sstevel@tonic-gate struct seg_info *seg; 17777c478bd9Sstevel@tonic-gate struct bank_info *bank_curr; 17787c478bd9Sstevel@tonic-gate struct mctrl_info *mctrl; 17797c478bd9Sstevel@tonic-gate mc_dlist_t *dgrp_ptr; 17807c478bd9Sstevel@tonic-gate mc_dlist_t *dev_ptr; 17817c478bd9Sstevel@tonic-gate uint64_t base; 17827c478bd9Sstevel@tonic-gate 17837c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 17847c478bd9Sstevel@tonic-gate 17857c478bd9Sstevel@tonic-gate /* delete mctrl_info */ 17867c478bd9Sstevel@tonic-gate if ((mctrl = (struct mctrl_info *)mc_node_get(mc_id, mctrl_head)) != 17877c478bd9Sstevel@tonic-gate NULL) { 17887c478bd9Sstevel@tonic-gate ndevgrps = mctrl->ndevgrps; 17897c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail); 17907c478bd9Sstevel@tonic-gate kmem_free(mctrl, sizeof (struct mctrl_info)); 17917c478bd9Sstevel@tonic-gate nmcs--; 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate /* 17947c478bd9Sstevel@tonic-gate * There is no other list left for disabled MC. 17957c478bd9Sstevel@tonic-gate */ 17967c478bd9Sstevel@tonic-gate if (ndevgrps == 0) { 17977c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 17987c478bd9Sstevel@tonic-gate return; 17997c478bd9Sstevel@tonic-gate } 18007c478bd9Sstevel@tonic-gate } else 18017c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "MC mlayout_del: mctrl is not found\n"); 18027c478bd9Sstevel@tonic-gate 18037c478bd9Sstevel@tonic-gate /* Delete device groups and devices of the detached MC */ 18047c478bd9Sstevel@tonic-gate for (i = 0; i < NDGRPS; i++) { 18057c478bd9Sstevel@tonic-gate dgrpid = mc_id * NDGRPS + i; 18067c478bd9Sstevel@tonic-gate if (!(dgrp_ptr = mc_node_get(dgrpid, dgrp_head))) { 18077c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mlayout_del: no devgrp %d\n", dgrpid); 18087c478bd9Sstevel@tonic-gate continue; 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate for (j = 0; j < NDIMMS; j++) { 18127c478bd9Sstevel@tonic-gate devid = dgrpid * NDIMMS + j; 18137c478bd9Sstevel@tonic-gate if (dev_ptr = mc_node_get(devid, device_head)) { 18147c478bd9Sstevel@tonic-gate mc_node_del(dev_ptr, &device_head, 18157c478bd9Sstevel@tonic-gate &device_tail); 18167c478bd9Sstevel@tonic-gate kmem_free(dev_ptr, sizeof (struct device_info)); 18177c478bd9Sstevel@tonic-gate } else { 18187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mlayout_del: no dev %d\n", 18197c478bd9Sstevel@tonic-gate devid); 18207c478bd9Sstevel@tonic-gate } 18217c478bd9Sstevel@tonic-gate } 18227c478bd9Sstevel@tonic-gate 18237c478bd9Sstevel@tonic-gate mc_node_del(dgrp_ptr, &dgrp_head, &dgrp_tail); 18247c478bd9Sstevel@tonic-gate kmem_free(dgrp_ptr, sizeof (struct dgrp_info)); 18257c478bd9Sstevel@tonic-gate } 18267c478bd9Sstevel@tonic-gate 18277c478bd9Sstevel@tonic-gate /* Delete banks and segments if it has no bank */ 18287c478bd9Sstevel@tonic-gate for (i = 0; i < NBANKS; i++) { 18297c478bd9Sstevel@tonic-gate bankid = mc_id * NBANKS + i; 18307c478bd9Sstevel@tonic-gate DPRINTF(MC_DESTRC_DEBUG, ("bank id %d\n", bankid)); 18317c478bd9Sstevel@tonic-gate if (!(bank_curr = (struct bank_info *)mc_node_get(bankid, 18327c478bd9Sstevel@tonic-gate bank_head))) { 18337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mlayout_del: no bank %d\n", bankid); 18347c478bd9Sstevel@tonic-gate continue; 18357c478bd9Sstevel@tonic-gate } 18367c478bd9Sstevel@tonic-gate 18377c478bd9Sstevel@tonic-gate if (bank_curr->valid) { 18387c478bd9Sstevel@tonic-gate base = bank_curr->um & ~bank_curr->uk; 18397c478bd9Sstevel@tonic-gate base <<= MADR_UPA_SHIFT; 18407c478bd9Sstevel@tonic-gate bank_curr->valid = 0; 18417c478bd9Sstevel@tonic-gate memsize -= bank_curr->size; 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate /* Delete bank at segment and segment if no bank left */ 18447c478bd9Sstevel@tonic-gate if (!(seg = seg_match_base(base))) { 18457c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mlayout_del: no seg\n"); 18467c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)bank_curr, &bank_head, 18477c478bd9Sstevel@tonic-gate &bank_tail); 18487c478bd9Sstevel@tonic-gate kmem_free(bank_curr, sizeof (struct bank_info)); 18497c478bd9Sstevel@tonic-gate continue; 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate /* update the bank list at the segment */ 18537c478bd9Sstevel@tonic-gate if (bank_curr->n_inseg == NULL) { 18547c478bd9Sstevel@tonic-gate /* node is at the tail of list */ 18557c478bd9Sstevel@tonic-gate seg->tb_inseg = bank_curr->p_inseg; 18567c478bd9Sstevel@tonic-gate } else { 18577c478bd9Sstevel@tonic-gate bank_curr->n_inseg->p_inseg = 18587c478bd9Sstevel@tonic-gate bank_curr->p_inseg; 18597c478bd9Sstevel@tonic-gate } 18607c478bd9Sstevel@tonic-gate 18617c478bd9Sstevel@tonic-gate if (bank_curr->p_inseg == NULL) { 18627c478bd9Sstevel@tonic-gate /* node is at the head of list */ 18637c478bd9Sstevel@tonic-gate seg->hb_inseg = bank_curr->n_inseg; 18647c478bd9Sstevel@tonic-gate } else { 18657c478bd9Sstevel@tonic-gate bank_curr->p_inseg->n_inseg = 18667c478bd9Sstevel@tonic-gate bank_curr->n_inseg; 18677c478bd9Sstevel@tonic-gate } 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate seg->nbanks--; 18707c478bd9Sstevel@tonic-gate seg->size -= bank_curr->size; 18717c478bd9Sstevel@tonic-gate 18727c478bd9Sstevel@tonic-gate if (seg->nbanks == 0) { 18737c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)seg, &seg_head, 18747c478bd9Sstevel@tonic-gate &seg_tail); 18757c478bd9Sstevel@tonic-gate kmem_free(seg, sizeof (struct seg_info)); 18767c478bd9Sstevel@tonic-gate nsegments--; 18777c478bd9Sstevel@tonic-gate } 18787c478bd9Sstevel@tonic-gate 18797c478bd9Sstevel@tonic-gate } 18807c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)bank_curr, &bank_head, &bank_tail); 18817c478bd9Sstevel@tonic-gate kmem_free(bank_curr, sizeof (struct bank_info)); 18827c478bd9Sstevel@tonic-gate } /* end of for loop for four banks */ 18837c478bd9Sstevel@tonic-gate 1884*d00f0155Sayznaga if (mc_dimm_sids && delete) { 1885*d00f0155Sayznaga rw_enter(&mcdimmsids_rw, RW_WRITER); 1886*d00f0155Sayznaga i = mc_get_sid_cache_index(mc_id); 1887*d00f0155Sayznaga if (i >= 0) { 1888*d00f0155Sayznaga mc_dimm_sids[i].state = MC_DIMM_SIDS_INVALID; 1889*d00f0155Sayznaga if (mc_dimm_sids[i].sids) { 1890*d00f0155Sayznaga kmem_free(mc_dimm_sids[i].sids, 1891*d00f0155Sayznaga sizeof (dimm_sid_t) * (NDGRPS * NDIMMS)); 1892*d00f0155Sayznaga mc_dimm_sids[i].sids = NULL; 1893*d00f0155Sayznaga } 1894*d00f0155Sayznaga } 1895*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 1896*d00f0155Sayznaga } 1897*d00f0155Sayznaga 18987c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* 19027c478bd9Sstevel@tonic-gate * Search the segment in the list starting at seg_head by base address 19037c478bd9Sstevel@tonic-gate * input: base address 19047c478bd9Sstevel@tonic-gate * return: pointer of found segment or null if not found. 19057c478bd9Sstevel@tonic-gate */ 19067c478bd9Sstevel@tonic-gate static struct seg_info * 19077c478bd9Sstevel@tonic-gate seg_match_base(u_longlong_t base) 19087c478bd9Sstevel@tonic-gate { 19097c478bd9Sstevel@tonic-gate static struct seg_info *seg_ptr; 19107c478bd9Sstevel@tonic-gate 19117c478bd9Sstevel@tonic-gate seg_ptr = (struct seg_info *)seg_head; 19127c478bd9Sstevel@tonic-gate while (seg_ptr != NULL) { 1913f47a9c50Smathue DPRINTF(MC_LIST_DEBUG, ("seg_match: base %lu,given base %llu\n", 19147c478bd9Sstevel@tonic-gate seg_ptr->base, base)); 19157c478bd9Sstevel@tonic-gate if (seg_ptr->base == base) 19167c478bd9Sstevel@tonic-gate break; 19177c478bd9Sstevel@tonic-gate seg_ptr = (struct seg_info *)seg_ptr->seg_node.next; 19187c478bd9Sstevel@tonic-gate } 19197c478bd9Sstevel@tonic-gate return (seg_ptr); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate /* 19237c478bd9Sstevel@tonic-gate * mc_dlist is a double linking list, including unique id, and pointers to 19247c478bd9Sstevel@tonic-gate * next, and previous nodes. seg_info, bank_info, dgrp_info, device_info, 19257c478bd9Sstevel@tonic-gate * and mctrl_info has it at the top to share the operations, add, del, and get. 19267c478bd9Sstevel@tonic-gate * 19277c478bd9Sstevel@tonic-gate * The new node is added at the tail and is not sorted. 19287c478bd9Sstevel@tonic-gate * 19297c478bd9Sstevel@tonic-gate * Input: The pointer of node to be added, head and tail of the list 19307c478bd9Sstevel@tonic-gate */ 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate static void 19337c478bd9Sstevel@tonic-gate mc_node_add(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail) 19347c478bd9Sstevel@tonic-gate { 19357c478bd9Sstevel@tonic-gate DPRINTF(MC_LIST_DEBUG, ("mc_node_add: node->id %d head %p tail %p\n", 19367c478bd9Sstevel@tonic-gate node->id, *head, *tail)); 19377c478bd9Sstevel@tonic-gate 19387c478bd9Sstevel@tonic-gate if (*head != NULL) { 19397c478bd9Sstevel@tonic-gate node->prev = *tail; 19407c478bd9Sstevel@tonic-gate node->next = (*tail)->next; 19417c478bd9Sstevel@tonic-gate (*tail)->next = node; 19427c478bd9Sstevel@tonic-gate *tail = node; 19437c478bd9Sstevel@tonic-gate } else { 19447c478bd9Sstevel@tonic-gate node->next = node->prev = NULL; 19457c478bd9Sstevel@tonic-gate *head = *tail = node; 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate } 19487c478bd9Sstevel@tonic-gate 19497c478bd9Sstevel@tonic-gate /* 19507c478bd9Sstevel@tonic-gate * Input: The pointer of node to be deleted, head and tail of the list 19517c478bd9Sstevel@tonic-gate * 19527c478bd9Sstevel@tonic-gate * Deleted node will be at the following positions 19537c478bd9Sstevel@tonic-gate * 1. At the tail of the list 19547c478bd9Sstevel@tonic-gate * 2. At the head of the list 19557c478bd9Sstevel@tonic-gate * 3. At the head and tail of the list, i.e. only one left. 19567c478bd9Sstevel@tonic-gate * 4. At the middle of the list 19577c478bd9Sstevel@tonic-gate */ 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate static void 19607c478bd9Sstevel@tonic-gate mc_node_del(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail) 19617c478bd9Sstevel@tonic-gate { 19627c478bd9Sstevel@tonic-gate if (node->next == NULL) { 19637c478bd9Sstevel@tonic-gate /* deleted node is at the tail of list */ 19647c478bd9Sstevel@tonic-gate *tail = node->prev; 19657c478bd9Sstevel@tonic-gate } else { 19667c478bd9Sstevel@tonic-gate node->next->prev = node->prev; 19677c478bd9Sstevel@tonic-gate } 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate if (node->prev == NULL) { 19707c478bd9Sstevel@tonic-gate /* deleted node is at the head of list */ 19717c478bd9Sstevel@tonic-gate *head = node->next; 19727c478bd9Sstevel@tonic-gate } else { 19737c478bd9Sstevel@tonic-gate node->prev->next = node->next; 19747c478bd9Sstevel@tonic-gate } 19757c478bd9Sstevel@tonic-gate } 19767c478bd9Sstevel@tonic-gate 19777c478bd9Sstevel@tonic-gate /* 19787c478bd9Sstevel@tonic-gate * Search the list from the head of the list to match the given id 19797c478bd9Sstevel@tonic-gate * Input: id and the head of the list 19807c478bd9Sstevel@tonic-gate * Return: pointer of found node 19817c478bd9Sstevel@tonic-gate */ 19827c478bd9Sstevel@tonic-gate static mc_dlist_t * 19837c478bd9Sstevel@tonic-gate mc_node_get(int id, mc_dlist_t *head) 19847c478bd9Sstevel@tonic-gate { 19857c478bd9Sstevel@tonic-gate mc_dlist_t *node; 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate node = head; 19887c478bd9Sstevel@tonic-gate while (node != NULL) { 19897c478bd9Sstevel@tonic-gate DPRINTF(MC_LIST_DEBUG, ("mc_node_get: id %d, given id %d\n", 19907c478bd9Sstevel@tonic-gate node->id, id)); 19917c478bd9Sstevel@tonic-gate if (node->id == id) 19927c478bd9Sstevel@tonic-gate break; 19937c478bd9Sstevel@tonic-gate node = node->next; 19947c478bd9Sstevel@tonic-gate } 19957c478bd9Sstevel@tonic-gate return (node); 19967c478bd9Sstevel@tonic-gate } 19977c478bd9Sstevel@tonic-gate 19987c478bd9Sstevel@tonic-gate /* 19997c478bd9Sstevel@tonic-gate * mc-us3 driver allows a platform to add extra label 20007c478bd9Sstevel@tonic-gate * information to the unum string. If a platform implements a 20017c478bd9Sstevel@tonic-gate * kernel function called plat_add_mem_unum_label() it will be 20027c478bd9Sstevel@tonic-gate * executed. This would typically be implemented in the platmod. 20037c478bd9Sstevel@tonic-gate */ 20047c478bd9Sstevel@tonic-gate static void 20057c478bd9Sstevel@tonic-gate mc_add_mem_unum_label(char *buf, int mcid, int bank, int dimm) 20067c478bd9Sstevel@tonic-gate { 20077c478bd9Sstevel@tonic-gate if (&plat_add_mem_unum_label) 20087c478bd9Sstevel@tonic-gate plat_add_mem_unum_label(buf, mcid, bank, dimm); 20097c478bd9Sstevel@tonic-gate } 2010*d00f0155Sayznaga 2011*d00f0155Sayznaga static int 2012*d00f0155Sayznaga mc_get_sid_cache_index(int mcid) 2013*d00f0155Sayznaga { 2014*d00f0155Sayznaga int i; 2015*d00f0155Sayznaga 2016*d00f0155Sayznaga for (i = 0; i < max_entries; i++) { 2017*d00f0155Sayznaga if (mcid == mc_dimm_sids[i].mcid) 2018*d00f0155Sayznaga return (i); 2019*d00f0155Sayznaga } 2020*d00f0155Sayznaga 2021*d00f0155Sayznaga return (-1); 2022*d00f0155Sayznaga } 2023*d00f0155Sayznaga 2024*d00f0155Sayznaga static int 2025*d00f0155Sayznaga mc_populate_sid_cache(void) 2026*d00f0155Sayznaga { 2027*d00f0155Sayznaga struct bank_info *bank; 2028*d00f0155Sayznaga 2029*d00f0155Sayznaga if (&plat_populate_sid_cache == 0) 2030*d00f0155Sayznaga return (ENOTSUP); 2031*d00f0155Sayznaga 2032*d00f0155Sayznaga ASSERT(RW_WRITE_HELD(&mcdimmsids_rw)); 2033*d00f0155Sayznaga 2034*d00f0155Sayznaga /* 2035*d00f0155Sayznaga * Mark which MCs are present and which segment 2036*d00f0155Sayznaga * the DIMMs belong to. Allocate space to 2037*d00f0155Sayznaga * store DIMM serial ids which are later provided 2038*d00f0155Sayznaga * by the platform layer, and update each bank_info 2039*d00f0155Sayznaga * structure with pointers to its serial ids. 2040*d00f0155Sayznaga */ 2041*d00f0155Sayznaga bank = (struct bank_info *)bank_head; 2042*d00f0155Sayznaga while (bank != NULL) { 2043*d00f0155Sayznaga int i, j; 2044*d00f0155Sayznaga int bankid, mcid, dgrp_no; 2045*d00f0155Sayznaga 2046*d00f0155Sayznaga if (!bank->valid) { 2047*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 2048*d00f0155Sayznaga continue; 2049*d00f0155Sayznaga } 2050*d00f0155Sayznaga 2051*d00f0155Sayznaga bankid = bank->bank_node.id; 2052*d00f0155Sayznaga mcid = bankid / NBANKS; 2053*d00f0155Sayznaga i = mc_get_sid_cache_index(mcid); 2054*d00f0155Sayznaga if (mc_dimm_sids[i].state == MC_DIMM_SIDS_AVAILABLE) { 2055*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 2056*d00f0155Sayznaga continue; 2057*d00f0155Sayznaga } else if (mc_dimm_sids[i].state != MC_DIMM_SIDS_REQUESTED) { 2058*d00f0155Sayznaga mc_dimm_sids[i].state = MC_DIMM_SIDS_REQUESTED; 2059*d00f0155Sayznaga mc_dimm_sids[i].seg_id = bank->seg_id; 2060*d00f0155Sayznaga } 2061*d00f0155Sayznaga 2062*d00f0155Sayznaga if (mc_dimm_sids[i].sids == NULL) { 2063*d00f0155Sayznaga mc_dimm_sids[i].sids = (dimm_sid_t *)kmem_zalloc( 2064*d00f0155Sayznaga sizeof (dimm_sid_t) * (NDGRPS * NDIMMS), KM_SLEEP); 2065*d00f0155Sayznaga } 2066*d00f0155Sayznaga 2067*d00f0155Sayznaga dgrp_no = bank->devgrp_id % NDGRPS; 2068*d00f0155Sayznaga 2069*d00f0155Sayznaga for (j = 0; j < NDIMMS; j++) 2070*d00f0155Sayznaga bank->dimmsidp[j] = 2071*d00f0155Sayznaga &mc_dimm_sids[i].sids[j + (NDIMMS * dgrp_no)]; 2072*d00f0155Sayznaga 2073*d00f0155Sayznaga bank = (struct bank_info *)bank->bank_node.next; 2074*d00f0155Sayznaga } 2075*d00f0155Sayznaga 2076*d00f0155Sayznaga 2077*d00f0155Sayznaga /* 2078*d00f0155Sayznaga * Call to the platform layer to populate the cache 2079*d00f0155Sayznaga * with DIMM serial ids. 2080*d00f0155Sayznaga */ 2081*d00f0155Sayznaga return (plat_populate_sid_cache(mc_dimm_sids, max_entries)); 2082*d00f0155Sayznaga } 2083*d00f0155Sayznaga 2084*d00f0155Sayznaga static void 2085*d00f0155Sayznaga mc_init_sid_cache_thr(void) 2086*d00f0155Sayznaga { 2087*d00f0155Sayznaga ASSERT(mc_dimm_sids == NULL); 2088*d00f0155Sayznaga 2089*d00f0155Sayznaga mutex_enter(&mcdatamutex); 2090*d00f0155Sayznaga rw_enter(&mcdimmsids_rw, RW_WRITER); 2091*d00f0155Sayznaga 2092*d00f0155Sayznaga mc_dimm_sids = plat_alloc_sid_cache(&max_entries); 2093*d00f0155Sayznaga (void) mc_populate_sid_cache(); 2094*d00f0155Sayznaga 2095*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 2096*d00f0155Sayznaga mutex_exit(&mcdatamutex); 2097*d00f0155Sayznaga } 2098*d00f0155Sayznaga 2099*d00f0155Sayznaga static int 2100*d00f0155Sayznaga mc_init_sid_cache(void) 2101*d00f0155Sayznaga { 2102*d00f0155Sayznaga if (&plat_alloc_sid_cache) { 2103*d00f0155Sayznaga (void) thread_create(NULL, 0, mc_init_sid_cache_thr, NULL, 0, 2104*d00f0155Sayznaga &p0, TS_RUN, minclsyspri); 2105*d00f0155Sayznaga return (0); 2106*d00f0155Sayznaga } else 2107*d00f0155Sayznaga return (ENOTSUP); 2108*d00f0155Sayznaga } 2109*d00f0155Sayznaga 2110*d00f0155Sayznaga static int 2111*d00f0155Sayznaga mc_get_mem_sid(int mcid, int dimm, char *buf, int buflen, int *lenp) 2112*d00f0155Sayznaga { 2113*d00f0155Sayznaga int i; 2114*d00f0155Sayznaga 2115*d00f0155Sayznaga if (buflen < DIMM_SERIAL_ID_LEN) 2116*d00f0155Sayznaga return (ENOSPC); 2117*d00f0155Sayznaga 2118*d00f0155Sayznaga /* 2119*d00f0155Sayznaga * If DIMM serial ids have not been cached yet, tell the 2120*d00f0155Sayznaga * caller to try again. 2121*d00f0155Sayznaga */ 2122*d00f0155Sayznaga if (!rw_tryenter(&mcdimmsids_rw, RW_READER)) 2123*d00f0155Sayznaga return (EAGAIN); 2124*d00f0155Sayznaga 2125*d00f0155Sayznaga if (mc_dimm_sids == NULL) { 2126*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 2127*d00f0155Sayznaga return (EAGAIN); 2128*d00f0155Sayznaga } 2129*d00f0155Sayznaga 2130*d00f0155Sayznaga /* 2131*d00f0155Sayznaga * Find dimm serial id using mcid and dimm # 2132*d00f0155Sayznaga */ 2133*d00f0155Sayznaga for (i = 0; i < max_entries; i++) { 2134*d00f0155Sayznaga if (mc_dimm_sids[i].mcid == mcid) 2135*d00f0155Sayznaga break; 2136*d00f0155Sayznaga } 2137*d00f0155Sayznaga if ((i == max_entries) || (!mc_dimm_sids[i].sids)) { 2138*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 2139*d00f0155Sayznaga return (ENOENT); 2140*d00f0155Sayznaga } 2141*d00f0155Sayznaga 2142*d00f0155Sayznaga (void) strlcpy(buf, mc_dimm_sids[i].sids[dimm], 2143*d00f0155Sayznaga DIMM_SERIAL_ID_LEN); 2144*d00f0155Sayznaga *lenp = strlen(buf); 2145*d00f0155Sayznaga 2146*d00f0155Sayznaga rw_exit(&mcdimmsids_rw); 2147*d00f0155Sayznaga return (0); 2148*d00f0155Sayznaga } 2149