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 5c311de31Sarutz * Common Development and Distribution License (the "License"). 6c311de31Sarutz * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 226684e119Spothier * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include <sys/types.h> 287c478bd9Sstevel@tonic-gate #include <sys/conf.h> 297c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 307c478bd9Sstevel@tonic-gate #include <sys/stat.h> 317c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 327c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 337c478bd9Sstevel@tonic-gate #include <sys/obpdefs.h> 347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 357c478bd9Sstevel@tonic-gate #include <sys/errno.h> 367c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 377c478bd9Sstevel@tonic-gate #include <sys/open.h> 387c478bd9Sstevel@tonic-gate #include <sys/thread.h> 397c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 407c478bd9Sstevel@tonic-gate #include <sys/x_call.h> 417c478bd9Sstevel@tonic-gate #include <sys/debug.h> 427c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 437c478bd9Sstevel@tonic-gate #include <sys/ivintr.h> 447c478bd9Sstevel@tonic-gate #include <sys/intr.h> 457c478bd9Sstevel@tonic-gate #include <sys/intreg.h> 467c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 477c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 487c478bd9Sstevel@tonic-gate #include <sys/spl.h> 497c478bd9Sstevel@tonic-gate #include <sys/async.h> 507c478bd9Sstevel@tonic-gate #include <sys/mc.h> 517c478bd9Sstevel@tonic-gate #include <sys/mc-us3i.h> 527c478bd9Sstevel@tonic-gate #include <sys/note.h> 537c478bd9Sstevel@tonic-gate #include <sys/cpu_module.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate * pm-hardware-state value 577c478bd9Sstevel@tonic-gate */ 587c478bd9Sstevel@tonic-gate #define NO_SUSPEND_RESUME "no-suspend-resume" 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate /* 617c478bd9Sstevel@tonic-gate * Function prototypes 627c478bd9Sstevel@tonic-gate */ 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static int mc_open(dev_t *, int, int, cred_t *); 657c478bd9Sstevel@tonic-gate static int mc_close(dev_t, int, int, cred_t *); 667c478bd9Sstevel@tonic-gate static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 677c478bd9Sstevel@tonic-gate static int mc_attach(dev_info_t *, ddi_attach_cmd_t); 687c478bd9Sstevel@tonic-gate static int mc_detach(dev_info_t *, ddi_detach_cmd_t); 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* 717c478bd9Sstevel@tonic-gate * Configuration data structures 727c478bd9Sstevel@tonic-gate */ 737c478bd9Sstevel@tonic-gate static struct cb_ops mc_cb_ops = { 747c478bd9Sstevel@tonic-gate mc_open, /* open */ 757c478bd9Sstevel@tonic-gate mc_close, /* close */ 767c478bd9Sstevel@tonic-gate nulldev, /* strategy */ 777c478bd9Sstevel@tonic-gate nulldev, /* print */ 787c478bd9Sstevel@tonic-gate nodev, /* dump */ 797c478bd9Sstevel@tonic-gate nulldev, /* read */ 807c478bd9Sstevel@tonic-gate nulldev, /* write */ 817c478bd9Sstevel@tonic-gate mc_ioctl, /* ioctl */ 827c478bd9Sstevel@tonic-gate nodev, /* devmap */ 837c478bd9Sstevel@tonic-gate nodev, /* mmap */ 847c478bd9Sstevel@tonic-gate nodev, /* segmap */ 857c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 867c478bd9Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 877c478bd9Sstevel@tonic-gate 0, /* streamtab */ 887c478bd9Sstevel@tonic-gate D_MP | D_NEW | D_HOTPLUG, /* Driver compatibility flag */ 897c478bd9Sstevel@tonic-gate CB_REV, /* rev */ 907c478bd9Sstevel@tonic-gate nodev, /* cb_aread */ 917c478bd9Sstevel@tonic-gate nodev /* cb_awrite */ 927c478bd9Sstevel@tonic-gate }; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate static struct dev_ops mc_ops = { 957c478bd9Sstevel@tonic-gate DEVO_REV, /* rev */ 967c478bd9Sstevel@tonic-gate 0, /* refcnt */ 977c478bd9Sstevel@tonic-gate ddi_no_info, /* getinfo */ 987c478bd9Sstevel@tonic-gate nulldev, /* identify */ 997c478bd9Sstevel@tonic-gate nulldev, /* probe */ 1007c478bd9Sstevel@tonic-gate mc_attach, /* attach */ 1017c478bd9Sstevel@tonic-gate mc_detach, /* detach */ 1027c478bd9Sstevel@tonic-gate nulldev, /* reset */ 1037c478bd9Sstevel@tonic-gate &mc_cb_ops, /* cb_ops */ 1047c478bd9Sstevel@tonic-gate (struct bus_ops *)0, /* bus_ops */ 105*19397407SSherry Moore nulldev, /* power */ 106*19397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 1077c478bd9Sstevel@tonic-gate }; 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* 1107c478bd9Sstevel@tonic-gate * Driver globals 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate static void *mcp; 1137c478bd9Sstevel@tonic-gate static int nmcs = 0; 1147c478bd9Sstevel@tonic-gate static int seg_id; 1157c478bd9Sstevel@tonic-gate static int nsegments; 1167c478bd9Sstevel@tonic-gate static uint64_t memsize; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate static uint_t mc_debug = 0; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate static int getreg; 1217c478bd9Sstevel@tonic-gate static int nregs; 1227c478bd9Sstevel@tonic-gate struct memory_reg_info *reg_info; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate static mc_dlist_t *seg_head, *seg_tail, *bank_head, *bank_tail; 1257c478bd9Sstevel@tonic-gate static mc_dlist_t *mctrl_head, *mctrl_tail, *dgrp_head, *dgrp_tail; 1267c478bd9Sstevel@tonic-gate static mc_dlist_t *device_head, *device_tail; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate static kmutex_t mcmutex; 1297c478bd9Sstevel@tonic-gate static kmutex_t mcdatamutex; 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1347c478bd9Sstevel@tonic-gate &mod_driverops, /* module type, this one is a driver */ 135*19397407SSherry Moore "Memory-controller: 1.14", /* module name */ 1367c478bd9Sstevel@tonic-gate &mc_ops, /* driver ops */ 1377c478bd9Sstevel@tonic-gate }; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1407c478bd9Sstevel@tonic-gate MODREV_1, /* rev */ 1417c478bd9Sstevel@tonic-gate (void *)&modldrv, 1427c478bd9Sstevel@tonic-gate NULL 1437c478bd9Sstevel@tonic-gate }; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static int mc_get_memory_reg_info(struct mc_soft_state *softsp); 1467c478bd9Sstevel@tonic-gate static void mc_construct(struct mc_soft_state *softsp); 1477c478bd9Sstevel@tonic-gate static void mc_delete(int mc_id); 1487c478bd9Sstevel@tonic-gate static void mc_node_add(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail); 1497c478bd9Sstevel@tonic-gate static void mc_node_del(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail); 1507c478bd9Sstevel@tonic-gate static void *mc_node_get(int id, mc_dlist_t *head); 1517c478bd9Sstevel@tonic-gate static void mc_add_mem_unum_label(char *unum, int mcid, int bank, int dimm); 1527c478bd9Sstevel@tonic-gate static int mc_get_mem_unum(int synd_code, uint64_t paddr, char *buf, 1537c478bd9Sstevel@tonic-gate int buflen, int *lenp); 1547c478bd9Sstevel@tonic-gate static int mc_get_mem_info(int synd_code, uint64_t paddr, 1557c478bd9Sstevel@tonic-gate uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep, 1567c478bd9Sstevel@tonic-gate int *segsp, int *banksp, int *mcidp); 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate #pragma weak p2get_mem_unum 1597c478bd9Sstevel@tonic-gate #pragma weak p2get_mem_info 1607c478bd9Sstevel@tonic-gate #pragma weak plat_add_mem_unum_label 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* For testing only */ 1637c478bd9Sstevel@tonic-gate struct test_unum { 1647c478bd9Sstevel@tonic-gate int synd_code; 1657c478bd9Sstevel@tonic-gate uint64_t paddr; 1667c478bd9Sstevel@tonic-gate char unum[UNUM_NAMLEN]; 1677c478bd9Sstevel@tonic-gate int len; 1687c478bd9Sstevel@tonic-gate }; 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * These are the module initialization routines. 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate int 1757c478bd9Sstevel@tonic-gate _init(void) 1767c478bd9Sstevel@tonic-gate { 1777c478bd9Sstevel@tonic-gate int error; 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate if ((error = ddi_soft_state_init(&mcp, 1807c478bd9Sstevel@tonic-gate sizeof (struct mc_soft_state), 1)) != 0) 1817c478bd9Sstevel@tonic-gate return (error); 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate error = mod_install(&modlinkage); 1847c478bd9Sstevel@tonic-gate if (error == 0) { 1857c478bd9Sstevel@tonic-gate mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL); 1867c478bd9Sstevel@tonic-gate mutex_init(&mcdatamutex, NULL, MUTEX_DRIVER, NULL); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate return (error); 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate int 1937c478bd9Sstevel@tonic-gate _fini(void) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate int error; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate if ((error = mod_remove(&modlinkage)) != 0) 1987c478bd9Sstevel@tonic-gate return (error); 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&mcp); 2017c478bd9Sstevel@tonic-gate mutex_destroy(&mcmutex); 2027c478bd9Sstevel@tonic-gate mutex_destroy(&mcdatamutex); 2037c478bd9Sstevel@tonic-gate return (0); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate int 2077c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2087c478bd9Sstevel@tonic-gate { 2097c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2107c478bd9Sstevel@tonic-gate } 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate static int 2137c478bd9Sstevel@tonic-gate mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2147c478bd9Sstevel@tonic-gate { 2157c478bd9Sstevel@tonic-gate struct mc_soft_state *softsp; 2167c478bd9Sstevel@tonic-gate struct dimm_info *dimminfop; 2177c478bd9Sstevel@tonic-gate int instance, len, err; 2187c478bd9Sstevel@tonic-gate int mcreg1_len; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate switch (cmd) { 2217c478bd9Sstevel@tonic-gate case DDI_ATTACH: 2227c478bd9Sstevel@tonic-gate break; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate case DDI_RESUME: 2257c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate default: 2287c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(mcp, instance) != DDI_SUCCESS) 2347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(mcp, instance); 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* Set the dip in the soft state */ 2397c478bd9Sstevel@tonic-gate softsp->dip = devi; 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate if ((softsp->portid = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->dip, 2427c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "portid", -1)) == -1) { 2437c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc%d: unable to get %s property\n", 2447c478bd9Sstevel@tonic-gate instance, "portid")); 2457c478bd9Sstevel@tonic-gate goto bad; 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc_attach: mc %d portid %d, cpuid %d\n", 2497c478bd9Sstevel@tonic-gate instance, softsp->portid, CPU->cpu_id)); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* Get the content of Memory Control Register I from obp */ 2527c478bd9Sstevel@tonic-gate mcreg1_len = sizeof (uint64_t); 2537c478bd9Sstevel@tonic-gate if ((ddi_getlongprop_buf(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS, 2547c478bd9Sstevel@tonic-gate "memory-control-register-1", (caddr_t)&(softsp->mcreg1), 2557c478bd9Sstevel@tonic-gate &mcreg1_len) == DDI_PROP_SUCCESS) && 2567c478bd9Sstevel@tonic-gate (mcreg1_len == sizeof (uint64_t))) { 2577c478bd9Sstevel@tonic-gate softsp->mcr_read_ok = 1; 2587c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc%d from obp: Reg1: 0x%lx\n", 2597c478bd9Sstevel@tonic-gate instance, softsp->mcreg1)); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* attach fails if mcreg1 cannot be accessed */ 2637c478bd9Sstevel@tonic-gate if (!softsp->mcr_read_ok) { 2647c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc%d: unable to get mcreg1\n", 2657c478bd9Sstevel@tonic-gate instance)); 2667c478bd9Sstevel@tonic-gate goto bad; 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate /* nothing to suspend/resume here */ 2707c478bd9Sstevel@tonic-gate (void) ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 2717c478bd9Sstevel@tonic-gate "pm-hardware-state", NO_SUSPEND_RESUME, 2727c478bd9Sstevel@tonic-gate sizeof (NO_SUSPEND_RESUME)); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * Get the label of dimms and pin routing information from the 2767c478bd9Sstevel@tonic-gate * memory-layout property of the memory controller. 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate err = ddi_getlongprop(DDI_DEV_T_ANY, softsp->dip, DDI_PROP_DONTPASS, 2797c478bd9Sstevel@tonic-gate "memory-layout", (caddr_t)&dimminfop, &len); 2807c478bd9Sstevel@tonic-gate if (err == DDI_PROP_SUCCESS && dimminfop->table_width == 1) { 2817c478bd9Sstevel@tonic-gate /* Set the pointer and size of property in the soft state */ 2827c478bd9Sstevel@tonic-gate softsp->memlayoutp = dimminfop; 2837c478bd9Sstevel@tonic-gate softsp->memlayoutlen = len; 2847c478bd9Sstevel@tonic-gate } else { 2857c478bd9Sstevel@tonic-gate /* 2867c478bd9Sstevel@tonic-gate * memory-layout property was not found or some other 2877c478bd9Sstevel@tonic-gate * error occured, plat_get_mem_unum() will not work 2887c478bd9Sstevel@tonic-gate * for this mc. 2897c478bd9Sstevel@tonic-gate */ 2907c478bd9Sstevel@tonic-gate softsp->memlayoutp = NULL; 2917c478bd9Sstevel@tonic-gate softsp->memlayoutlen = 0; 2927c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, 2937c478bd9Sstevel@tonic-gate ("mc %d: missing or unsupported memory-layout property\n", 2947c478bd9Sstevel@tonic-gate instance)); 2957c478bd9Sstevel@tonic-gate } 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate mutex_enter(&mcmutex); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate /* Get the physical segments from memory/reg, just once for all MC */ 3007c478bd9Sstevel@tonic-gate if (!getreg) { 3017c478bd9Sstevel@tonic-gate if (mc_get_memory_reg_info(softsp) != 0) { 3027c478bd9Sstevel@tonic-gate goto bad1; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate getreg = 1; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate /* Construct the physical and logical layout of the MC */ 3087c478bd9Sstevel@tonic-gate mc_construct(softsp); 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate if (nmcs == 1) { 3117c478bd9Sstevel@tonic-gate if (&p2get_mem_unum) 3127c478bd9Sstevel@tonic-gate p2get_mem_unum = mc_get_mem_unum; 3137c478bd9Sstevel@tonic-gate if (&p2get_mem_info) 3147c478bd9Sstevel@tonic-gate p2get_mem_info = mc_get_mem_info; 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "mc-us3i", S_IFCHR, instance, 3187c478bd9Sstevel@tonic-gate "ddi_mem_ctrl", 0) != DDI_SUCCESS) { 3197c478bd9Sstevel@tonic-gate DPRINTF(MC_ATTACH_DEBUG, ("mc_attach: create_minor_node" 3207c478bd9Sstevel@tonic-gate " failed \n")); 3217c478bd9Sstevel@tonic-gate goto bad1; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate mutex_exit(&mcmutex); 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 3267c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate bad1: 3297c478bd9Sstevel@tonic-gate /* release all allocated data struture for this MC */ 3307c478bd9Sstevel@tonic-gate mc_delete(softsp->portid); 3317c478bd9Sstevel@tonic-gate mutex_exit(&mcmutex); 3327c478bd9Sstevel@tonic-gate if (softsp->memlayoutp != NULL) 3337c478bd9Sstevel@tonic-gate kmem_free(softsp->memlayoutp, softsp->memlayoutlen); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate bad: 3367c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "mc-us3i: attach failed for instance %d\n", instance); 3377c478bd9Sstevel@tonic-gate ddi_soft_state_free(mcp, instance); 3387c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3417c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3427c478bd9Sstevel@tonic-gate static int 3437c478bd9Sstevel@tonic-gate mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 3447c478bd9Sstevel@tonic-gate { 3457c478bd9Sstevel@tonic-gate int instance; 3467c478bd9Sstevel@tonic-gate struct mc_soft_state *softsp; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate /* get the instance of this devi */ 3497c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate /* get the soft state pointer for this device node */ 3527c478bd9Sstevel@tonic-gate softsp = ddi_get_soft_state(mcp, instance); 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate switch (cmd) { 3557c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 3567c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate case DDI_DETACH: 3597c478bd9Sstevel@tonic-gate break; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate default: 3627c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate DPRINTF(MC_DETACH_DEBUG, ("mc %d DETACH: portid %d\n", instance, 3667c478bd9Sstevel@tonic-gate softsp->portid)); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate mutex_enter(&mcmutex); 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate /* release all allocated data struture for this MC */ 3717c478bd9Sstevel@tonic-gate mc_delete(softsp->portid); 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate if (softsp->memlayoutp != NULL) 3747c478bd9Sstevel@tonic-gate kmem_free(softsp->memlayoutp, softsp->memlayoutlen); 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate if (nmcs == 0) { 3777c478bd9Sstevel@tonic-gate if (&p2get_mem_unum) 3787c478bd9Sstevel@tonic-gate p2get_mem_unum = NULL; 3797c478bd9Sstevel@tonic-gate if (&p2get_mem_info) 3807c478bd9Sstevel@tonic-gate p2get_mem_info = NULL; 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate mutex_exit(&mcmutex); 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 3867c478bd9Sstevel@tonic-gate /* free up the soft state */ 3877c478bd9Sstevel@tonic-gate ddi_soft_state_free(mcp, instance); 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3937c478bd9Sstevel@tonic-gate static int 3947c478bd9Sstevel@tonic-gate mc_open(dev_t *devp, int flag, int otyp, cred_t *credp) 3957c478bd9Sstevel@tonic-gate { 3967c478bd9Sstevel@tonic-gate int status = 0; 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate /* verify that otyp is appropriate */ 3997c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) { 4007c478bd9Sstevel@tonic-gate return (EINVAL); 4017c478bd9Sstevel@tonic-gate } 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate mutex_enter(&mcmutex); 4047c478bd9Sstevel@tonic-gate /* At least one attached? */ 4057c478bd9Sstevel@tonic-gate if (nmcs == 0) { 4067c478bd9Sstevel@tonic-gate status = ENXIO; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate mutex_exit(&mcmutex); 409446fbcf9Smb158278 4107c478bd9Sstevel@tonic-gate return (status); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate 4137c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4147c478bd9Sstevel@tonic-gate static int 4157c478bd9Sstevel@tonic-gate mc_close(dev_t devp, int flag, int otyp, cred_t *credp) 4167c478bd9Sstevel@tonic-gate { 4177c478bd9Sstevel@tonic-gate return (0); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate /* 4217c478bd9Sstevel@tonic-gate * cmd includes MCIOC_MEMCONF, MCIOC_MEM, MCIOC_SEG, MCIOC_BANK, MCIOC_DEVGRP, 4227c478bd9Sstevel@tonic-gate * MCIOC_CTRLCONF, MCIOC_CONTROL. 4237c478bd9Sstevel@tonic-gate * 4247c478bd9Sstevel@tonic-gate * MCIOC_MEM, MCIOC_SEG, MCIOC_CTRLCONF, and MCIOC_CONTROL are 4257c478bd9Sstevel@tonic-gate * associated with various length struct. If given number is less than the 4267c478bd9Sstevel@tonic-gate * number in kernel, update the number and return EINVAL so that user could 4277c478bd9Sstevel@tonic-gate * allocate enough space for it. 4287c478bd9Sstevel@tonic-gate * 4297c478bd9Sstevel@tonic-gate */ 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4327c478bd9Sstevel@tonic-gate static int 4337c478bd9Sstevel@tonic-gate mc_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, 4347c478bd9Sstevel@tonic-gate int *rval_p) 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate size_t size; 4377c478bd9Sstevel@tonic-gate struct mc_memconf mcmconf; 4387c478bd9Sstevel@tonic-gate struct mc_memory *mcmem, mcmem_in; 4397c478bd9Sstevel@tonic-gate struct mc_segment *mcseg, mcseg_in; 4407c478bd9Sstevel@tonic-gate struct mc_bank mcbank; 4417c478bd9Sstevel@tonic-gate struct mc_devgrp mcdevgrp; 4427c478bd9Sstevel@tonic-gate struct mc_ctrlconf *mcctrlconf, mcctrlconf_in; 4437c478bd9Sstevel@tonic-gate struct mc_control *mccontrol, mccontrol_in; 4447c478bd9Sstevel@tonic-gate struct seg_info *seg = NULL; 4457c478bd9Sstevel@tonic-gate struct bank_info *bank = NULL; 4467c478bd9Sstevel@tonic-gate struct dgrp_info *dgrp = NULL; 4477c478bd9Sstevel@tonic-gate struct mctrl_info *mcport; 4487c478bd9Sstevel@tonic-gate mc_dlist_t *mctrl; 4497c478bd9Sstevel@tonic-gate int i, status = 0; 4507c478bd9Sstevel@tonic-gate cpu_t *cpu; 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate switch (cmd) { 4537c478bd9Sstevel@tonic-gate case MCIOC_MEMCONF: 4547c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate mcmconf.nmcs = nmcs; 4577c478bd9Sstevel@tonic-gate mcmconf.nsegments = nsegments; 4587c478bd9Sstevel@tonic-gate mcmconf.nbanks = NLOGBANKS_PER_SEG; 4597c478bd9Sstevel@tonic-gate mcmconf.ndevgrps = NDGRPS_PER_MC; 4607c478bd9Sstevel@tonic-gate mcmconf.ndevs = NDIMMS_PER_DGRP; 4617c478bd9Sstevel@tonic-gate mcmconf.len_dev = MAX_DEVLEN; 4627c478bd9Sstevel@tonic-gate mcmconf.xfer_size = TRANSFER_SIZE; 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if (copyout(&mcmconf, (void *)arg, sizeof (mcmconf))) 4677c478bd9Sstevel@tonic-gate return (EFAULT); 4687c478bd9Sstevel@tonic-gate return (0); 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate /* 4717c478bd9Sstevel@tonic-gate * input: nsegments and allocate space for various length of segmentids 4727c478bd9Sstevel@tonic-gate * 4737c478bd9Sstevel@tonic-gate * return 0: size, number of segments, and all segment ids, 4747c478bd9Sstevel@tonic-gate * where glocal and local ids are identical. 4757c478bd9Sstevel@tonic-gate * EINVAL: if the given nsegments is less than that in kernel and 4767c478bd9Sstevel@tonic-gate * nsegments of struct will be updated. 4777c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 4787c478bd9Sstevel@tonic-gate */ 4797c478bd9Sstevel@tonic-gate case MCIOC_MEM: 4807c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcmem_in, sizeof (mcmem_in)) != 0) 4817c478bd9Sstevel@tonic-gate return (EFAULT); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 4847c478bd9Sstevel@tonic-gate if (mcmem_in.nsegments < nsegments) { 4857c478bd9Sstevel@tonic-gate mcmem_in.nsegments = nsegments; 4867c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 4877c478bd9Sstevel@tonic-gate if (copyout(&mcmem_in, (void *)arg, sizeof (mcmem_in))) 4887c478bd9Sstevel@tonic-gate status = EFAULT; 4897c478bd9Sstevel@tonic-gate else 4907c478bd9Sstevel@tonic-gate status = EINVAL; 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate return (status); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate size = sizeof (*mcmem) + (nsegments - 1) * 4967c478bd9Sstevel@tonic-gate sizeof (mcmem->segmentids[0]); 4977c478bd9Sstevel@tonic-gate mcmem = kmem_zalloc(size, KM_SLEEP); 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate mcmem->size = memsize; 5007c478bd9Sstevel@tonic-gate mcmem->nsegments = nsegments; 5017c478bd9Sstevel@tonic-gate seg = (struct seg_info *)seg_head; 5027c478bd9Sstevel@tonic-gate for (i = 0; i < nsegments; i++) { 5037c478bd9Sstevel@tonic-gate ASSERT(seg != NULL); 5047c478bd9Sstevel@tonic-gate mcmem->segmentids[i].globalid = seg->seg_node.id; 5057c478bd9Sstevel@tonic-gate mcmem->segmentids[i].localid = seg->seg_node.id; 5067c478bd9Sstevel@tonic-gate seg = (struct seg_info *)seg->seg_node.next; 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate if (copyout(mcmem, (void *)arg, size)) 5117c478bd9Sstevel@tonic-gate status = EFAULT; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate kmem_free(mcmem, size); 5147c478bd9Sstevel@tonic-gate return (status); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /* 5177c478bd9Sstevel@tonic-gate * input: id, nbanks and allocate space for various length of bankids 5187c478bd9Sstevel@tonic-gate * 5197c478bd9Sstevel@tonic-gate * return 0: base, size, number of banks, and all bank ids, 5207c478bd9Sstevel@tonic-gate * where global id is unique of all banks and local id 5217c478bd9Sstevel@tonic-gate * is only unique for mc. 5227c478bd9Sstevel@tonic-gate * EINVAL: either id isn't found or if given nbanks is less than 5237c478bd9Sstevel@tonic-gate * that in kernel and nbanks of struct will be updated. 5247c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 5257c478bd9Sstevel@tonic-gate */ 5267c478bd9Sstevel@tonic-gate case MCIOC_SEG: 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcseg_in, sizeof (mcseg_in)) != 0) 5297c478bd9Sstevel@tonic-gate return (EFAULT); 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 5327c478bd9Sstevel@tonic-gate if ((seg = mc_node_get(mcseg_in.id, seg_head)) == NULL) { 5337c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG: seg not match, " 5347c478bd9Sstevel@tonic-gate "id %d\n", mcseg_in.id)); 5357c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 5367c478bd9Sstevel@tonic-gate return (EFAULT); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate 5397c478bd9Sstevel@tonic-gate if (mcseg_in.nbanks < seg->nbanks) { 5407c478bd9Sstevel@tonic-gate mcseg_in.nbanks = seg->nbanks; 5417c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 5427c478bd9Sstevel@tonic-gate if (copyout(&mcseg_in, (void *)arg, sizeof (mcseg_in))) 5437c478bd9Sstevel@tonic-gate status = EFAULT; 5447c478bd9Sstevel@tonic-gate else 5457c478bd9Sstevel@tonic-gate status = EINVAL; 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate return (status); 5487c478bd9Sstevel@tonic-gate } 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate size = sizeof (*mcseg) + (seg->nbanks - 1) * 5517c478bd9Sstevel@tonic-gate sizeof (mcseg->bankids[0]); 5527c478bd9Sstevel@tonic-gate mcseg = kmem_zalloc(size, KM_SLEEP); 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate mcseg->id = seg->seg_node.id; 5557c478bd9Sstevel@tonic-gate mcseg->ifactor = seg->ifactor; 5567c478bd9Sstevel@tonic-gate mcseg->base = seg->base; 5577c478bd9Sstevel@tonic-gate mcseg->size = seg->size; 5587c478bd9Sstevel@tonic-gate mcseg->nbanks = seg->nbanks; 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate bank = seg->head; 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG:nbanks %d seg %p bank %p\n", 5637c478bd9Sstevel@tonic-gate seg->nbanks, (void *) seg, (void *) bank)); 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate i = 0; 5667c478bd9Sstevel@tonic-gate while (bank != NULL) { 5677c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_SEG:idx %d bank_id %d\n", 5687c478bd9Sstevel@tonic-gate i, bank->bank_node.id)); 5697c478bd9Sstevel@tonic-gate mcseg->bankids[i].globalid = bank->bank_node.id; 5707c478bd9Sstevel@tonic-gate mcseg->bankids[i++].localid = bank->local_id; 5717c478bd9Sstevel@tonic-gate bank = bank->next; 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate ASSERT(i == seg->nbanks); 5747c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate if (copyout(mcseg, (void *)arg, size)) 5777c478bd9Sstevel@tonic-gate status = EFAULT; 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate kmem_free(mcseg, size); 5807c478bd9Sstevel@tonic-gate return (status); 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* 5837c478bd9Sstevel@tonic-gate * input: id 5847c478bd9Sstevel@tonic-gate * 5857c478bd9Sstevel@tonic-gate * return 0: mask, match, size, and devgrpid, 5867c478bd9Sstevel@tonic-gate * where global id is unique of all devgrps and local id 5877c478bd9Sstevel@tonic-gate * is only unique for mc. 5887c478bd9Sstevel@tonic-gate * EINVAL: if id isn't found 5897c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate case MCIOC_BANK: 5927c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcbank, sizeof (mcbank)) != 0) 5937c478bd9Sstevel@tonic-gate return (EFAULT); 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_BANK: bank id %d\n", mcbank.id)); 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate if ((bank = mc_node_get(mcbank.id, bank_head)) == NULL) { 6007c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6017c478bd9Sstevel@tonic-gate return (EINVAL); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate mcbank.mask = bank->mask; 6057c478bd9Sstevel@tonic-gate mcbank.match = bank->match; 6067c478bd9Sstevel@tonic-gate mcbank.size = bank->size; 6077c478bd9Sstevel@tonic-gate mcbank.devgrpid.globalid = bank->devgrp_id; 6087c478bd9Sstevel@tonic-gate mcbank.devgrpid.localid = 6097c478bd9Sstevel@tonic-gate bank->bank_node.id % NLOGBANKS_PER_SEG; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6127c478bd9Sstevel@tonic-gate 6137c478bd9Sstevel@tonic-gate if (copyout(&mcbank, (void *)arg, sizeof (mcbank))) 6147c478bd9Sstevel@tonic-gate return (EFAULT); 6157c478bd9Sstevel@tonic-gate return (0); 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate /* 6187c478bd9Sstevel@tonic-gate * input:id and allocate space for various length of deviceids 6197c478bd9Sstevel@tonic-gate * 6207c478bd9Sstevel@tonic-gate * return 0: size and number of devices. 6217c478bd9Sstevel@tonic-gate * EINVAL: id isn't found 6227c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 6237c478bd9Sstevel@tonic-gate */ 6247c478bd9Sstevel@tonic-gate case MCIOC_DEVGRP: 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcdevgrp, sizeof (mcdevgrp)) != 0) 6277c478bd9Sstevel@tonic-gate return (EFAULT); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 6307c478bd9Sstevel@tonic-gate if ((dgrp = mc_node_get(mcdevgrp.id, dgrp_head)) == NULL) { 6317c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_DEVGRP: not match, id " 6327c478bd9Sstevel@tonic-gate "%d\n", mcdevgrp.id)); 6337c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6347c478bd9Sstevel@tonic-gate return (EINVAL); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate mcdevgrp.ndevices = dgrp->ndevices; 6387c478bd9Sstevel@tonic-gate mcdevgrp.size = dgrp->size; 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6417c478bd9Sstevel@tonic-gate 6427c478bd9Sstevel@tonic-gate if (copyout(&mcdevgrp, (void *)arg, sizeof (mcdevgrp))) 6437c478bd9Sstevel@tonic-gate status = EFAULT; 6447c478bd9Sstevel@tonic-gate 6457c478bd9Sstevel@tonic-gate return (status); 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* 6487c478bd9Sstevel@tonic-gate * input: nmcs and allocate space for various length of mcids 6497c478bd9Sstevel@tonic-gate * 6507c478bd9Sstevel@tonic-gate * return 0: number of mc, and all mcids, 6517c478bd9Sstevel@tonic-gate * where glocal and local ids are identical. 6527c478bd9Sstevel@tonic-gate * EINVAL: if the given nmcs is less than that in kernel and 6537c478bd9Sstevel@tonic-gate * nmcs of struct will be updated. 6547c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 6557c478bd9Sstevel@tonic-gate */ 6567c478bd9Sstevel@tonic-gate case MCIOC_CTRLCONF: 6577c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mcctrlconf_in, 6587c478bd9Sstevel@tonic-gate sizeof (mcctrlconf_in)) != 0) 6597c478bd9Sstevel@tonic-gate return (EFAULT); 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 6627c478bd9Sstevel@tonic-gate if (mcctrlconf_in.nmcs < nmcs) { 6637c478bd9Sstevel@tonic-gate mcctrlconf_in.nmcs = nmcs; 6647c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6657c478bd9Sstevel@tonic-gate if (copyout(&mcctrlconf_in, (void *)arg, 6667c478bd9Sstevel@tonic-gate sizeof (mcctrlconf_in))) 6677c478bd9Sstevel@tonic-gate status = EFAULT; 6687c478bd9Sstevel@tonic-gate else 6697c478bd9Sstevel@tonic-gate status = EINVAL; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate return (status); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate /* 6757c478bd9Sstevel@tonic-gate * Cannot just use the size of the struct because of the various 6767c478bd9Sstevel@tonic-gate * length struct 6777c478bd9Sstevel@tonic-gate */ 6787c478bd9Sstevel@tonic-gate size = sizeof (*mcctrlconf) + ((nmcs - 1) * 6797c478bd9Sstevel@tonic-gate sizeof (mcctrlconf->mcids[0])); 6807c478bd9Sstevel@tonic-gate mcctrlconf = kmem_zalloc(size, KM_SLEEP); 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate mcctrlconf->nmcs = nmcs; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate /* Get all MC ids and add to mcctrlconf */ 6857c478bd9Sstevel@tonic-gate mctrl = mctrl_head; 6867c478bd9Sstevel@tonic-gate i = 0; 6877c478bd9Sstevel@tonic-gate while (mctrl != NULL) { 6887c478bd9Sstevel@tonic-gate mcctrlconf->mcids[i].globalid = mctrl->id; 6897c478bd9Sstevel@tonic-gate mcctrlconf->mcids[i].localid = mctrl->id; 6907c478bd9Sstevel@tonic-gate i++; 6917c478bd9Sstevel@tonic-gate mctrl = mctrl->next; 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate ASSERT(i == nmcs); 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate if (copyout(mcctrlconf, (void *)arg, size)) 6987c478bd9Sstevel@tonic-gate status = EFAULT; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate kmem_free(mcctrlconf, size); 7017c478bd9Sstevel@tonic-gate return (status); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate /* 7047c478bd9Sstevel@tonic-gate * input:id, ndevgrps and allocate space for various length of devgrpids 7057c478bd9Sstevel@tonic-gate * 7067c478bd9Sstevel@tonic-gate * return 0: number of devgrp, and all devgrpids, 7077c478bd9Sstevel@tonic-gate * is unique of all devgrps and local id is only unique 7087c478bd9Sstevel@tonic-gate * for mc. 7097c478bd9Sstevel@tonic-gate * EINVAL: either if id isn't found or if the given ndevgrps is 7107c478bd9Sstevel@tonic-gate * less than that in kernel and ndevgrps of struct will 7117c478bd9Sstevel@tonic-gate * be updated. 7127c478bd9Sstevel@tonic-gate * EFAULT: if other errors in kernel. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate case MCIOC_CONTROL: 7157c478bd9Sstevel@tonic-gate if (copyin((void *)arg, &mccontrol_in, 7167c478bd9Sstevel@tonic-gate sizeof (mccontrol_in)) != 0) 7177c478bd9Sstevel@tonic-gate return (EFAULT); 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 7207c478bd9Sstevel@tonic-gate if ((mcport = mc_node_get(mccontrol_in.id, 7217c478bd9Sstevel@tonic-gate mctrl_head)) == NULL) { 7227c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 7237c478bd9Sstevel@tonic-gate return (EINVAL); 7247c478bd9Sstevel@tonic-gate } 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate /* 7277c478bd9Sstevel@tonic-gate * mcport->ndevgrps zero means Memory Controller is disable. 7287c478bd9Sstevel@tonic-gate */ 7297c478bd9Sstevel@tonic-gate if ((mccontrol_in.ndevgrps < mcport->ndevgrps) || 7307c478bd9Sstevel@tonic-gate (mcport->ndevgrps == 0)) { 7317c478bd9Sstevel@tonic-gate mccontrol_in.ndevgrps = mcport->ndevgrps; 7327c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 7337c478bd9Sstevel@tonic-gate if (copyout(&mccontrol_in, (void *)arg, 7347c478bd9Sstevel@tonic-gate sizeof (mccontrol_in))) 7357c478bd9Sstevel@tonic-gate status = EFAULT; 7367c478bd9Sstevel@tonic-gate else if (mcport->ndevgrps != 0) 7377c478bd9Sstevel@tonic-gate status = EINVAL; 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate return (status); 7407c478bd9Sstevel@tonic-gate } 7417c478bd9Sstevel@tonic-gate 7427c478bd9Sstevel@tonic-gate size = sizeof (*mccontrol) + (mcport->ndevgrps - 1) * 7437c478bd9Sstevel@tonic-gate sizeof (mccontrol->devgrpids[0]); 7447c478bd9Sstevel@tonic-gate mccontrol = kmem_zalloc(size, KM_SLEEP); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate mccontrol->id = mcport->mctrl_node.id; 7477c478bd9Sstevel@tonic-gate mccontrol->ndevgrps = mcport->ndevgrps; 7487c478bd9Sstevel@tonic-gate for (i = 0; i < mcport->ndevgrps; i++) { 7497c478bd9Sstevel@tonic-gate mccontrol->devgrpids[i].globalid = mcport->devgrpids[i]; 7507c478bd9Sstevel@tonic-gate mccontrol->devgrpids[i].localid = 7517c478bd9Sstevel@tonic-gate mcport->devgrpids[i] % NDGRPS_PER_MC; 7527c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("MCIOC_CONTROL: devgrp id %d\n", 7537c478bd9Sstevel@tonic-gate i)); 7547c478bd9Sstevel@tonic-gate } 7557c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate if (copyout(mccontrol, (void *)arg, size)) 7587c478bd9Sstevel@tonic-gate status = EFAULT; 7597c478bd9Sstevel@tonic-gate 7607c478bd9Sstevel@tonic-gate kmem_free(mccontrol, size); 7617c478bd9Sstevel@tonic-gate return (status); 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate /* 7647c478bd9Sstevel@tonic-gate * input:id 7657c478bd9Sstevel@tonic-gate * 7667c478bd9Sstevel@tonic-gate * return 0: CPU flushed successfully. 7677c478bd9Sstevel@tonic-gate * EINVAL: the id wasn't found 7687c478bd9Sstevel@tonic-gate */ 7697c478bd9Sstevel@tonic-gate case MCIOC_ECFLUSH: 7707c478bd9Sstevel@tonic-gate mutex_enter(&cpu_lock); 7717c478bd9Sstevel@tonic-gate cpu = cpu_get((processorid_t)arg); 7727c478bd9Sstevel@tonic-gate mutex_exit(&cpu_lock); 7737c478bd9Sstevel@tonic-gate if (cpu == NULL) 7747c478bd9Sstevel@tonic-gate return (EINVAL); 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate xc_one(arg, (xcfunc_t *)cpu_flush_ecache, 0, 0); 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate return (0); 7797c478bd9Sstevel@tonic-gate 7807c478bd9Sstevel@tonic-gate default: 7817c478bd9Sstevel@tonic-gate DPRINTF(MC_CMD_DEBUG, ("DEFAULT: cmd is wrong\n")); 7827c478bd9Sstevel@tonic-gate return (EFAULT); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate /* 7877c478bd9Sstevel@tonic-gate * Gets the reg property from the memory node. This provides the various 7887c478bd9Sstevel@tonic-gate * memory segments, at bank-boundries, dimm-pair boundries, in the form 7897c478bd9Sstevel@tonic-gate * of [base, size] pairs. Continuous segments, spanning boundries are 7907c478bd9Sstevel@tonic-gate * merged into one. 7917c478bd9Sstevel@tonic-gate * Returns 0 for success and -1 for failure. 7927c478bd9Sstevel@tonic-gate */ 7937c478bd9Sstevel@tonic-gate static int 7947c478bd9Sstevel@tonic-gate mc_get_memory_reg_info(struct mc_soft_state *softsp) 7957c478bd9Sstevel@tonic-gate { 7967c478bd9Sstevel@tonic-gate dev_info_t *devi; 7977c478bd9Sstevel@tonic-gate int len; 7987c478bd9Sstevel@tonic-gate int i; 7997c478bd9Sstevel@tonic-gate struct memory_reg_info *mregi; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate _NOTE(ARGUNUSED(softsp)) 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate if ((devi = ddi_find_devinfo("memory", -1, 0)) == NULL) { 8047c478bd9Sstevel@tonic-gate DPRINTF(MC_REG_DEBUG, 8057c478bd9Sstevel@tonic-gate ("mc-us3i: cannot find memory node under root\n")); 8067c478bd9Sstevel@tonic-gate return (-1); 8077c478bd9Sstevel@tonic-gate } 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, devi, DDI_PROP_DONTPASS, 8107c478bd9Sstevel@tonic-gate "reg", (caddr_t)®_info, &len) != DDI_PROP_SUCCESS) { 8117c478bd9Sstevel@tonic-gate DPRINTF(MC_REG_DEBUG, 8127c478bd9Sstevel@tonic-gate ("mc-us3i: reg undefined under memory\n")); 8137c478bd9Sstevel@tonic-gate return (-1); 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate nregs = len/sizeof (*mregi); 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate DPRINTF(MC_REG_DEBUG, ("mc_get_memory_reg_info: nregs %d" 8197c478bd9Sstevel@tonic-gate "reg_info %p\n", nregs, (void *) reg_info)); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate mregi = reg_info; 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* debug printfs */ 8247c478bd9Sstevel@tonic-gate for (i = 0; i < nregs; i++) { 8257c478bd9Sstevel@tonic-gate DPRINTF(MC_REG_DEBUG, (" [0x%lx, 0x%lx] ", 8267c478bd9Sstevel@tonic-gate mregi->base, mregi->size)); 8277c478bd9Sstevel@tonic-gate mregi++; 8287c478bd9Sstevel@tonic-gate } 8297c478bd9Sstevel@tonic-gate 8307c478bd9Sstevel@tonic-gate return (0); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * Initialize a logical bank 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate static struct bank_info * 8377c478bd9Sstevel@tonic-gate mc_add_bank(int bankid, uint64_t mask, uint64_t match, uint64_t size, 8387c478bd9Sstevel@tonic-gate int dgrpid) 8397c478bd9Sstevel@tonic-gate { 8407c478bd9Sstevel@tonic-gate struct bank_info *banki; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate if ((banki = mc_node_get(bankid, bank_head)) != NULL) { 8437c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_bank: bank %d exists\n", 8447c478bd9Sstevel@tonic-gate bankid)); 8457c478bd9Sstevel@tonic-gate return (banki); 8467c478bd9Sstevel@tonic-gate } 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate banki = kmem_zalloc(sizeof (*banki), KM_SLEEP); 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate banki->bank_node.id = bankid; 8517c478bd9Sstevel@tonic-gate banki->devgrp_id = dgrpid; 8527c478bd9Sstevel@tonic-gate banki->mask = mask; 8537c478bd9Sstevel@tonic-gate banki->match = match; 8547c478bd9Sstevel@tonic-gate banki->base = match; 8557c478bd9Sstevel@tonic-gate banki->size = size; 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)banki, &bank_head, &bank_tail); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_bank: id %d mask 0x%lx match 0x%lx" 8607c478bd9Sstevel@tonic-gate " base 0x%lx size 0x%lx\n", bankid, mask, match, 8617c478bd9Sstevel@tonic-gate banki->base, banki->size)); 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate return (banki); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate 8667c478bd9Sstevel@tonic-gate /* 8677c478bd9Sstevel@tonic-gate * Use the bank's base address to find out whether to initialize a new segment, 8687c478bd9Sstevel@tonic-gate * or weave the bank into an existing segment. If the tail bank of a previous 8697c478bd9Sstevel@tonic-gate * segment is not continuous with the new bank, the new bank goes into a new 8707c478bd9Sstevel@tonic-gate * segment. 8717c478bd9Sstevel@tonic-gate */ 8727c478bd9Sstevel@tonic-gate static void 8737c478bd9Sstevel@tonic-gate mc_add_segment(struct bank_info *banki) 8747c478bd9Sstevel@tonic-gate { 8757c478bd9Sstevel@tonic-gate struct seg_info *segi; 8767c478bd9Sstevel@tonic-gate struct bank_info *tb; 8777c478bd9Sstevel@tonic-gate 8787c478bd9Sstevel@tonic-gate /* does this bank start a new segment? */ 8797c478bd9Sstevel@tonic-gate if ((segi = mc_node_get(seg_id, seg_head)) == NULL) { 8807c478bd9Sstevel@tonic-gate /* this should happen for the first segment only */ 8817c478bd9Sstevel@tonic-gate goto new_seg; 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate tb = segi->tail; 8857c478bd9Sstevel@tonic-gate /* discontiguous banks go into a new segment, increment the seg_id */ 8867c478bd9Sstevel@tonic-gate if (banki->base > (tb->base + tb->size)) { 8877c478bd9Sstevel@tonic-gate seg_id++; 8887c478bd9Sstevel@tonic-gate goto new_seg; 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate /* weave the bank into the segment */ 8927c478bd9Sstevel@tonic-gate segi->nbanks++; 8937c478bd9Sstevel@tonic-gate tb->next = banki; 8947c478bd9Sstevel@tonic-gate 8957c478bd9Sstevel@tonic-gate banki->seg_id = segi->seg_node.id; 8967c478bd9Sstevel@tonic-gate banki->local_id = tb->local_id + 1; 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* contiguous or interleaved? */ 8997c478bd9Sstevel@tonic-gate if (banki->base != (tb->base + tb->size)) 9007c478bd9Sstevel@tonic-gate segi->ifactor++; 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate segi->size += banki->size; 9037c478bd9Sstevel@tonic-gate segi->tail = banki; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate memsize += banki->size; 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_segment: id %d add bank: id %d" 9087c478bd9Sstevel@tonic-gate "size 0x%lx\n", segi->seg_node.id, banki->bank_node.id, 9097c478bd9Sstevel@tonic-gate banki->size)); 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate return; 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate new_seg: 9147c478bd9Sstevel@tonic-gate segi = kmem_zalloc(sizeof (*segi), KM_SLEEP); 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate segi->seg_node.id = seg_id; 9177c478bd9Sstevel@tonic-gate segi->nbanks = 1; 9187c478bd9Sstevel@tonic-gate segi->ifactor = 1; 9197c478bd9Sstevel@tonic-gate segi->base = banki->base; 9207c478bd9Sstevel@tonic-gate segi->size = banki->size; 9217c478bd9Sstevel@tonic-gate segi->head = banki; 9227c478bd9Sstevel@tonic-gate segi->tail = banki; 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate banki->seg_id = segi->seg_node.id; 9257c478bd9Sstevel@tonic-gate banki->local_id = 0; 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)segi, &seg_head, &seg_tail); 9287c478bd9Sstevel@tonic-gate nsegments++; 9297c478bd9Sstevel@tonic-gate 9307c478bd9Sstevel@tonic-gate memsize += banki->size; 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_segment: id %d new bank: id %d" 9337c478bd9Sstevel@tonic-gate "size 0x%lx\n", segi->seg_node.id, banki->bank_node.id, 9347c478bd9Sstevel@tonic-gate banki->size)); 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate /* 9387c478bd9Sstevel@tonic-gate * Returns the address bit number (row index) that controls the logical/external 9397c478bd9Sstevel@tonic-gate * bank assignment in interleave of kind internal-external same dimm-pair, 9407c478bd9Sstevel@tonic-gate * internal-external both dimm-pair. This is done by using the dimm-densities 9417c478bd9Sstevel@tonic-gate * and part-type. 9427c478bd9Sstevel@tonic-gate */ 9437c478bd9Sstevel@tonic-gate static int 9447c478bd9Sstevel@tonic-gate get_row_shift(int row_index, struct dgrp_info *dgrp) 9457c478bd9Sstevel@tonic-gate { 9467c478bd9Sstevel@tonic-gate int shift; 9477c478bd9Sstevel@tonic-gate 9487c478bd9Sstevel@tonic-gate switch (dgrp->base_device) { 9497c478bd9Sstevel@tonic-gate case BASE_DEVICE_128Mb: 9507c478bd9Sstevel@tonic-gate case BASE_DEVICE_256Mb: 9517c478bd9Sstevel@tonic-gate /* 128Mb and 256Mb devices have same bank select mask */ 9527c478bd9Sstevel@tonic-gate shift = ADDR_GEN_128Mb_X8_ROW_0; 9537c478bd9Sstevel@tonic-gate break; 9547c478bd9Sstevel@tonic-gate case BASE_DEVICE_512Mb: 9557c478bd9Sstevel@tonic-gate case BASE_DEVICE_1Gb: 9567c478bd9Sstevel@tonic-gate /* 512 and 1Gb devices have same bank select mask */ 9577c478bd9Sstevel@tonic-gate shift = ADDR_GEN_512Mb_X8_ROW_0; 9587c478bd9Sstevel@tonic-gate break; 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (dgrp->part_type == PART_TYPE_X4) 9627c478bd9Sstevel@tonic-gate shift += 1; 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate shift += row_index; 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate return (shift); 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate static void 9717c478bd9Sstevel@tonic-gate get_device_select(int interleave, struct dgrp_info *dgrp, 9727c478bd9Sstevel@tonic-gate int *ds_shift, int *bs_shift) 9737c478bd9Sstevel@tonic-gate { 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate switch (interleave) { 9767c478bd9Sstevel@tonic-gate case INTERLEAVE_DISABLE: 9777c478bd9Sstevel@tonic-gate /* Fall Through */ 9787c478bd9Sstevel@tonic-gate case INTERLEAVE_INTERNAL: 9797c478bd9Sstevel@tonic-gate /* Bit 33 selects the dimm group/pair */ 9807c478bd9Sstevel@tonic-gate *ds_shift = DIMM_PAIR_SELECT_SHIFT; 9817c478bd9Sstevel@tonic-gate if (dgrp->nlogbanks == 2) { 9827c478bd9Sstevel@tonic-gate /* Bit 32 selects the logical bank */ 9837c478bd9Sstevel@tonic-gate *bs_shift = LOG_BANK_SELECT_SHIFT; 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate break; 9867c478bd9Sstevel@tonic-gate case INTERLEAVE_INTEXT_SAME_DIMM_PAIR: 9877c478bd9Sstevel@tonic-gate /* Bit 33 selects the dimm group/pair */ 9887c478bd9Sstevel@tonic-gate *ds_shift = DIMM_PAIR_SELECT_SHIFT; 9897c478bd9Sstevel@tonic-gate if (dgrp->nlogbanks == 2) { 9907c478bd9Sstevel@tonic-gate /* Row[2] selects the logical bank */ 9917c478bd9Sstevel@tonic-gate *bs_shift = get_row_shift(2, dgrp); 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate break; 9947c478bd9Sstevel@tonic-gate case INTERLEAVE_INTEXT_BOTH_DIMM_PAIR: 9957c478bd9Sstevel@tonic-gate if (dgrp->nlogbanks == 2) { 9967c478bd9Sstevel@tonic-gate /* Row[3] selects the dimm group/pair */ 9977c478bd9Sstevel@tonic-gate *ds_shift = get_row_shift(3, dgrp); 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate /* Row[2] selects the logical bank */ 10007c478bd9Sstevel@tonic-gate *bs_shift = get_row_shift(2, dgrp); 10017c478bd9Sstevel@tonic-gate } else { 10027c478bd9Sstevel@tonic-gate /* Row[2] selects the dimm group/pair */ 10037c478bd9Sstevel@tonic-gate *ds_shift = get_row_shift(2, dgrp); 10047c478bd9Sstevel@tonic-gate } 10057c478bd9Sstevel@tonic-gate break; 10067c478bd9Sstevel@tonic-gate } 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate static void 10107c478bd9Sstevel@tonic-gate mc_add_xor_banks(struct mctrl_info *mctrl, 10117c478bd9Sstevel@tonic-gate uint64_t mask, uint64_t match, int interleave) 10127c478bd9Sstevel@tonic-gate { 10137c478bd9Sstevel@tonic-gate int i, j, nbits, nbanks; 10147c478bd9Sstevel@tonic-gate int bankid; 10157c478bd9Sstevel@tonic-gate int dselect[4]; 10167c478bd9Sstevel@tonic-gate int ds_shift = -1, bs_shift = -1; 10177c478bd9Sstevel@tonic-gate uint64_t id, size, xmatch; 10187c478bd9Sstevel@tonic-gate struct bank_info *banki; 10197c478bd9Sstevel@tonic-gate struct dgrp_info *dgrp; 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate /* xor mode - assume 2 identical dimm-pairs */ 10227c478bd9Sstevel@tonic-gate if ((dgrp = mc_node_get(mctrl->devgrpids[0], dgrp_head)) == NULL) { 10237c478bd9Sstevel@tonic-gate return; 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate get_device_select(interleave, dgrp, &ds_shift, &bs_shift); 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate mask |= (ds_shift == -1 ? 0 : (1ULL << ds_shift)); 10297c478bd9Sstevel@tonic-gate mask |= (bs_shift == -1 ? 0 : (1ULL << bs_shift)); 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate /* xor enable means, bit 21 is used for dimm-pair select */ 10327c478bd9Sstevel@tonic-gate mask |= XOR_DEVICE_SELECT_MASK; 10337c478bd9Sstevel@tonic-gate if (dgrp->nlogbanks == NLOGBANKS_PER_DGRP) { 10347c478bd9Sstevel@tonic-gate /* bit 20 is used for logbank select */ 10357c478bd9Sstevel@tonic-gate mask |= XOR_BANK_SELECT_MASK; 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate /* find out the bits set to 1 in mask, nbits can be 2 or 4 */ 10397c478bd9Sstevel@tonic-gate nbits = 0; 10407c478bd9Sstevel@tonic-gate for (i = 0; i <= DIMM_PAIR_SELECT_SHIFT; i++) { 10417c478bd9Sstevel@tonic-gate if ((((mask >> i) & 1) == 1) && (nbits < 4)) { 10427c478bd9Sstevel@tonic-gate dselect[nbits] = i; 10437c478bd9Sstevel@tonic-gate nbits++; 10447c478bd9Sstevel@tonic-gate } 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate /* number or banks can be 4 or 16 */ 10487c478bd9Sstevel@tonic-gate nbanks = 1 << nbits; 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate size = (dgrp->size * 2)/nbanks; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate bankid = mctrl->mctrl_node.id * NLOGBANKS_PER_MC; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate /* each bit position of the mask decides the match & base for bank */ 10557c478bd9Sstevel@tonic-gate for (i = 0; i < nbanks; i++) { 10567c478bd9Sstevel@tonic-gate xmatch = 0; 10577c478bd9Sstevel@tonic-gate for (j = 0; j < nbits; j++) { 10587c478bd9Sstevel@tonic-gate xmatch |= (i & (1ULL << j)) << (dselect[j] - j); 10597c478bd9Sstevel@tonic-gate } 10607c478bd9Sstevel@tonic-gate /* xor ds bits to get the dimm-pair */ 10617c478bd9Sstevel@tonic-gate id = ((xmatch & (1ULL << ds_shift)) >> ds_shift) ^ 10627c478bd9Sstevel@tonic-gate ((xmatch & (1ULL << XOR_DEVICE_SELECT_SHIFT)) >> 10637c478bd9Sstevel@tonic-gate XOR_DEVICE_SELECT_SHIFT); 10647c478bd9Sstevel@tonic-gate banki = mc_add_bank(bankid, mask, match | xmatch, size, 10657c478bd9Sstevel@tonic-gate mctrl->devgrpids[id]); 10667c478bd9Sstevel@tonic-gate mc_add_segment(banki); 10677c478bd9Sstevel@tonic-gate bankid++; 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate /* 10727c478bd9Sstevel@tonic-gate * Based on interleave, dimm-densities, part-type determine the mask 10737c478bd9Sstevel@tonic-gate * and match per bank, construct the logical layout by adding segments 10747c478bd9Sstevel@tonic-gate * and banks 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate static int 10777c478bd9Sstevel@tonic-gate mc_add_dgrp_banks(uint64_t bankid, uint64_t dgrpid, 10787c478bd9Sstevel@tonic-gate uint64_t mask, uint64_t match, int interleave) 10797c478bd9Sstevel@tonic-gate { 10807c478bd9Sstevel@tonic-gate int nbanks = 0; 10817c478bd9Sstevel@tonic-gate struct bank_info *banki; 10827c478bd9Sstevel@tonic-gate struct dgrp_info *dgrp; 10837c478bd9Sstevel@tonic-gate int ds_shift = -1, bs_shift = -1; 10847c478bd9Sstevel@tonic-gate uint64_t size; 10857c478bd9Sstevel@tonic-gate uint64_t match_save; 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate if ((dgrp = mc_node_get(dgrpid, dgrp_head)) == NULL) { 10887c478bd9Sstevel@tonic-gate return (0); 10897c478bd9Sstevel@tonic-gate } 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate get_device_select(interleave, dgrp, &ds_shift, &bs_shift); 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate mask |= (ds_shift == -1 ? 0 : (1ULL << ds_shift)); 10947c478bd9Sstevel@tonic-gate mask |= (bs_shift == -1 ? 0 : (1ULL << bs_shift)); 10957c478bd9Sstevel@tonic-gate match |= (ds_shift == -1 ? 0 : ((dgrpid & 1) << ds_shift)); 10967c478bd9Sstevel@tonic-gate match_save = match; 10977c478bd9Sstevel@tonic-gate size = dgrp->size/dgrp->nlogbanks; 10987c478bd9Sstevel@tonic-gate 10997c478bd9Sstevel@tonic-gate /* for bankid 0, 2, 4 .. */ 11007c478bd9Sstevel@tonic-gate match |= (bs_shift == -1 ? 0 : ((bankid & 1) << bs_shift)); 11017c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_segments: interleave %d" 11027c478bd9Sstevel@tonic-gate " mask 0x%lx bs_shift %d match 0x%lx\n", 11037c478bd9Sstevel@tonic-gate interleave, mask, bs_shift, match)); 11047c478bd9Sstevel@tonic-gate banki = mc_add_bank(bankid, mask, match, size, dgrpid); 11057c478bd9Sstevel@tonic-gate nbanks++; 11067c478bd9Sstevel@tonic-gate mc_add_segment(banki); 11077c478bd9Sstevel@tonic-gate 11087c478bd9Sstevel@tonic-gate if (dgrp->nlogbanks == 2) { 11097c478bd9Sstevel@tonic-gate /* 11107c478bd9Sstevel@tonic-gate * Set match value to original before adding second 11117c478bd9Sstevel@tonic-gate * logical bank interleaving information. 11127c478bd9Sstevel@tonic-gate */ 11137c478bd9Sstevel@tonic-gate match = match_save; 11147c478bd9Sstevel@tonic-gate bankid++; 11157c478bd9Sstevel@tonic-gate match |= (bs_shift == -1 ? 0 : ((bankid & 1) << bs_shift)); 11167c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_segments: interleave %d" 11177c478bd9Sstevel@tonic-gate " mask 0x%lx shift %d match 0x%lx\n", 11187c478bd9Sstevel@tonic-gate interleave, mask, bs_shift, match)); 11197c478bd9Sstevel@tonic-gate banki = mc_add_bank(bankid, mask, match, size, dgrpid); 11207c478bd9Sstevel@tonic-gate nbanks++; 11217c478bd9Sstevel@tonic-gate mc_add_segment(banki); 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate return (nbanks); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate /* 11287c478bd9Sstevel@tonic-gate * Construct the logical layout 11297c478bd9Sstevel@tonic-gate */ 11307c478bd9Sstevel@tonic-gate static void 11317c478bd9Sstevel@tonic-gate mc_logical_layout(struct mctrl_info *mctrl, struct mc_soft_state *softsp) 11327c478bd9Sstevel@tonic-gate { 11337c478bd9Sstevel@tonic-gate int i; 11347c478bd9Sstevel@tonic-gate uint64_t mcid, bankid, interleave, mask, match; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate if (mctrl->ndevgrps == 0) 11377c478bd9Sstevel@tonic-gate return; 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate mcid = mctrl->mctrl_node.id; 11407c478bd9Sstevel@tonic-gate mask = MC_SELECT_MASK; 11417c478bd9Sstevel@tonic-gate match = mcid << MC_SELECT_SHIFT; 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate interleave = (softsp->mcreg1 & MCREG1_INTERLEAVE_MASK) >> 11447c478bd9Sstevel@tonic-gate MCREG1_INTERLEAVE_SHIFT; 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* Two dimm pairs and xor bit set */ 11477c478bd9Sstevel@tonic-gate if (mctrl->ndevgrps == NDGRPS_PER_MC && 11487c478bd9Sstevel@tonic-gate (softsp->mcreg1 & MCREG1_XOR_ENABLE)) { 11497c478bd9Sstevel@tonic-gate mc_add_xor_banks(mctrl, mask, match, interleave); 11507c478bd9Sstevel@tonic-gate return; 11517c478bd9Sstevel@tonic-gate } 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /* 11547c478bd9Sstevel@tonic-gate * For xor bit unset or only one dimm pair. 11557c478bd9Sstevel@tonic-gate * In one dimm pair case, even if xor bit is set, xor 11567c478bd9Sstevel@tonic-gate * interleaving is only taking place in dimm's internal 11577c478bd9Sstevel@tonic-gate * banks. Dimm and external bank select bits are the 11587c478bd9Sstevel@tonic-gate * same as those without xor bit set. 11597c478bd9Sstevel@tonic-gate */ 11607c478bd9Sstevel@tonic-gate bankid = mcid * NLOGBANKS_PER_MC; 11617c478bd9Sstevel@tonic-gate for (i = 0; i < mctrl->ndevgrps; i++) { 11627c478bd9Sstevel@tonic-gate bankid += mc_add_dgrp_banks(bankid, mctrl->devgrpids[i], 11637c478bd9Sstevel@tonic-gate mask, match, interleave); 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate /* 11687c478bd9Sstevel@tonic-gate * Get the dimm-pair's size from the reg_info 11697c478bd9Sstevel@tonic-gate */ 11707c478bd9Sstevel@tonic-gate static uint64_t 11717c478bd9Sstevel@tonic-gate get_devgrp_size(uint64_t start) 11727c478bd9Sstevel@tonic-gate { 11737c478bd9Sstevel@tonic-gate int i; 11747c478bd9Sstevel@tonic-gate uint64_t size; 11757c478bd9Sstevel@tonic-gate uint64_t end, reg_start, reg_end; 11767c478bd9Sstevel@tonic-gate struct memory_reg_info *regi; 11777c478bd9Sstevel@tonic-gate 11787c478bd9Sstevel@tonic-gate /* dgrp end address */ 11797c478bd9Sstevel@tonic-gate end = start + DGRP_SIZE_MAX - 1; 11807c478bd9Sstevel@tonic-gate 11817c478bd9Sstevel@tonic-gate regi = reg_info; 11827c478bd9Sstevel@tonic-gate size = 0; 11837c478bd9Sstevel@tonic-gate for (i = 0; i < nregs; i++) { 11847c478bd9Sstevel@tonic-gate reg_start = regi->base; 11857c478bd9Sstevel@tonic-gate reg_end = regi->base + regi->size - 1; 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate /* completely outside */ 11887c478bd9Sstevel@tonic-gate if ((reg_end < start) || (reg_start > end)) { 11897c478bd9Sstevel@tonic-gate regi++; 11907c478bd9Sstevel@tonic-gate continue; 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate /* completely inside */ 11947c478bd9Sstevel@tonic-gate if ((reg_start <= start) && (reg_end >= end)) { 11957c478bd9Sstevel@tonic-gate return (DGRP_SIZE_MAX); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate /* start is inside, but not the end, get the remainder */ 11997c478bd9Sstevel@tonic-gate if (reg_start < start) { 12007c478bd9Sstevel@tonic-gate size = regi->size - (start - reg_start); 12017c478bd9Sstevel@tonic-gate regi++; 12027c478bd9Sstevel@tonic-gate continue; 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /* add up size for all within range */ 12067c478bd9Sstevel@tonic-gate size += regi->size; 12077c478bd9Sstevel@tonic-gate regi++; 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate return (size); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate /* 12147c478bd9Sstevel@tonic-gate * Each device group is a pair (dimm-pair) of identical single/dual dimms. 12157c478bd9Sstevel@tonic-gate * Determine the dimm-pair's dimm-densities and part-type using the MCR-I. 12167c478bd9Sstevel@tonic-gate */ 12177c478bd9Sstevel@tonic-gate static void 12187c478bd9Sstevel@tonic-gate mc_add_devgrp(int dgrpid, struct mc_soft_state *softsp) 12197c478bd9Sstevel@tonic-gate { 12207c478bd9Sstevel@tonic-gate int i, mcid, devid, dgrpoffset; 12217c478bd9Sstevel@tonic-gate struct dgrp_info *dgrp; 12227c478bd9Sstevel@tonic-gate struct device_info *dev; 12237c478bd9Sstevel@tonic-gate struct dimm_info *dimmp = (struct dimm_info *)softsp->memlayoutp; 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate mcid = softsp->portid; 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate /* add the entry on dgrp_info list */ 12287c478bd9Sstevel@tonic-gate if ((dgrp = mc_node_get(dgrpid, dgrp_head)) != NULL) { 12297c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_devgrp: devgrp %d exists\n", 12307c478bd9Sstevel@tonic-gate dgrpid)); 12317c478bd9Sstevel@tonic-gate return; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate dgrp = kmem_zalloc(sizeof (*dgrp), KM_SLEEP); 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate dgrp->dgrp_node.id = dgrpid; 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate /* a devgrp has identical (type & size) pair */ 12397c478bd9Sstevel@tonic-gate if ((dgrpid & 1) == 0) { 12407c478bd9Sstevel@tonic-gate /* dimm-pair 0, 2, 4, 6 */ 12417c478bd9Sstevel@tonic-gate if (softsp->mcreg1 & MCREG1_DIMM1_BANK1) 12427c478bd9Sstevel@tonic-gate dgrp->nlogbanks = 2; 12437c478bd9Sstevel@tonic-gate else 12447c478bd9Sstevel@tonic-gate dgrp->nlogbanks = 1; 12457c478bd9Sstevel@tonic-gate dgrp->base_device = (softsp->mcreg1 & MCREG1_ADDRGEN1_MASK) >> 12467c478bd9Sstevel@tonic-gate MCREG1_ADDRGEN1_SHIFT; 12477c478bd9Sstevel@tonic-gate dgrp->part_type = (softsp->mcreg1 & MCREG1_X4DIMM1_MASK) >> 12487c478bd9Sstevel@tonic-gate MCREG1_X4DIMM1_SHIFT; 12497c478bd9Sstevel@tonic-gate } else { 12507c478bd9Sstevel@tonic-gate /* dimm-pair 1, 3, 5, 7 */ 12517c478bd9Sstevel@tonic-gate if (softsp->mcreg1 & MCREG1_DIMM2_BANK3) 12527c478bd9Sstevel@tonic-gate dgrp->nlogbanks = 2; 12537c478bd9Sstevel@tonic-gate else 12547c478bd9Sstevel@tonic-gate dgrp->nlogbanks = 1; 12557c478bd9Sstevel@tonic-gate dgrp->base_device = (softsp->mcreg1 & MCREG1_ADDRGEN2_MASK) >> 12567c478bd9Sstevel@tonic-gate MCREG1_ADDRGEN2_SHIFT; 12577c478bd9Sstevel@tonic-gate dgrp->part_type = (softsp->mcreg1 & MCREG1_X4DIMM2_MASK) >> 12587c478bd9Sstevel@tonic-gate MCREG1_X4DIMM2_SHIFT; 12597c478bd9Sstevel@tonic-gate } 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate dgrp->base = MC_BASE(mcid) + DGRP_BASE(dgrpid); 12627c478bd9Sstevel@tonic-gate dgrp->size = get_devgrp_size(dgrp->base); 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_devgrp: id %d size %ld logbanks %d" 12657c478bd9Sstevel@tonic-gate " base_device %d part_type %d\n", dgrpid, dgrp->size, 12667c478bd9Sstevel@tonic-gate dgrp->nlogbanks, dgrp->base_device, dgrp->part_type)); 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate dgrpoffset = dgrpid % NDGRPS_PER_MC; 12697c478bd9Sstevel@tonic-gate dgrp->ndevices = NDIMMS_PER_DGRP; 12707c478bd9Sstevel@tonic-gate /* add the entry for the (identical) pair of dimms/device */ 12717c478bd9Sstevel@tonic-gate for (i = 0; i < NDIMMS_PER_DGRP; i++) { 12727c478bd9Sstevel@tonic-gate devid = dgrpid * NDIMMS_PER_DGRP + i; 12737c478bd9Sstevel@tonic-gate dgrp->deviceids[i] = devid; 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate if ((dev = mc_node_get(devid, device_head)) != NULL) { 12767c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_devgrp: device %d " 12777c478bd9Sstevel@tonic-gate "exists\n", devid)); 12787c478bd9Sstevel@tonic-gate continue; 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 12827c478bd9Sstevel@tonic-gate 12837c478bd9Sstevel@tonic-gate dev->dev_node.id = devid; 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate dev->size = dgrp->size/2; 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate if (dimmp) { 12887c478bd9Sstevel@tonic-gate (void) strncpy(dev->label, (char *)dimmp->label[ 12897c478bd9Sstevel@tonic-gate i + NDIMMS_PER_DGRP * dgrpoffset], 12907c478bd9Sstevel@tonic-gate MAX_DEVLEN); 12917c478bd9Sstevel@tonic-gate 12927c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_add_devgrp: dimm %d %s\n", 12937c478bd9Sstevel@tonic-gate dev->dev_node.id, dev->label)); 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate 12967c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)dev, &device_head, &device_tail); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)dgrp, &dgrp_head, &dgrp_tail); 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate /* 13037c478bd9Sstevel@tonic-gate * Construct the physical and logical layout 13047c478bd9Sstevel@tonic-gate */ 13057c478bd9Sstevel@tonic-gate static void 13067c478bd9Sstevel@tonic-gate mc_construct(struct mc_soft_state *softsp) 13077c478bd9Sstevel@tonic-gate { 13087c478bd9Sstevel@tonic-gate int i, mcid, dgrpid; 13097c478bd9Sstevel@tonic-gate struct mctrl_info *mctrl; 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate mcid = softsp->portid; 13127c478bd9Sstevel@tonic-gate 13137c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_construct: mcid %d, mcreg1 0x%lx\n", 13147c478bd9Sstevel@tonic-gate mcid, softsp->mcreg1)); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate /* 13177c478bd9Sstevel@tonic-gate * Construct the Physical & Logical Layout 13187c478bd9Sstevel@tonic-gate */ 13197c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate /* allocate for mctrl_info */ 13227c478bd9Sstevel@tonic-gate if ((mctrl = mc_node_get(mcid, mctrl_head)) != NULL) { 13237c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_construct: mctrl %d exists\n", 13247c478bd9Sstevel@tonic-gate mcid)); 13257c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 13267c478bd9Sstevel@tonic-gate return; 13277c478bd9Sstevel@tonic-gate } 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate mctrl = kmem_zalloc(sizeof (*mctrl), KM_SLEEP); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate mctrl->mctrl_node.id = mcid; 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate i = 0; 13347c478bd9Sstevel@tonic-gate dgrpid = mcid * NDGRPS_PER_MC; 13357c478bd9Sstevel@tonic-gate if (softsp->mcreg1 & MCREG1_DIMM1_BANK0) { 13367c478bd9Sstevel@tonic-gate mc_add_devgrp(dgrpid, softsp); 13377c478bd9Sstevel@tonic-gate mctrl->devgrpids[i] = dgrpid; 13387c478bd9Sstevel@tonic-gate mctrl->ndevgrps++; 13397c478bd9Sstevel@tonic-gate i++; 13407c478bd9Sstevel@tonic-gate } 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate if (softsp->mcreg1 & MCREG1_DIMM2_BANK2) { 13437c478bd9Sstevel@tonic-gate dgrpid++; 13447c478bd9Sstevel@tonic-gate mc_add_devgrp(dgrpid, softsp); 13457c478bd9Sstevel@tonic-gate mctrl->devgrpids[i] = dgrpid; 13467c478bd9Sstevel@tonic-gate mctrl->ndevgrps++; 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate mc_logical_layout(mctrl, softsp); 13507c478bd9Sstevel@tonic-gate 13517c478bd9Sstevel@tonic-gate mctrl->dimminfop = (struct dimm_info *)softsp->memlayoutp; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate nmcs++; 13547c478bd9Sstevel@tonic-gate mc_node_add((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail); 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate DPRINTF(MC_CNSTRC_DEBUG, ("mc_construct: nmcs %d memsize %ld" 13597c478bd9Sstevel@tonic-gate "nsegments %d\n", nmcs, memsize, nsegments)); 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate /* 13637c478bd9Sstevel@tonic-gate * Delete nodes related to the given MC on mc, device group, device, 13647c478bd9Sstevel@tonic-gate * and bank lists. Moreover, delete corresponding segment if its connected 13657c478bd9Sstevel@tonic-gate * banks are all removed. 13667c478bd9Sstevel@tonic-gate */ 13677c478bd9Sstevel@tonic-gate static void 13687c478bd9Sstevel@tonic-gate mc_delete(int mc_id) 13697c478bd9Sstevel@tonic-gate { 13707c478bd9Sstevel@tonic-gate int i, j, dgrpid, devid, bankid; 13717c478bd9Sstevel@tonic-gate struct mctrl_info *mctrl; 13727c478bd9Sstevel@tonic-gate struct dgrp_info *dgrp; 13737c478bd9Sstevel@tonic-gate struct device_info *devp; 13747c478bd9Sstevel@tonic-gate struct seg_info *segi; 13757c478bd9Sstevel@tonic-gate struct bank_info *banki; 13767c478bd9Sstevel@tonic-gate 13777c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate /* delete mctrl_info */ 13807c478bd9Sstevel@tonic-gate if ((mctrl = mc_node_get(mc_id, mctrl_head)) != NULL) { 13817c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)mctrl, &mctrl_head, &mctrl_tail); 13827c478bd9Sstevel@tonic-gate kmem_free(mctrl, sizeof (*mctrl)); 13837c478bd9Sstevel@tonic-gate nmcs--; 13847c478bd9Sstevel@tonic-gate } else 13857c478bd9Sstevel@tonic-gate DPRINTF(MC_DESTRC_DEBUG, ("mc_delete: mctrl is not found\n")); 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate /* delete device groups and devices of the detached MC */ 13887c478bd9Sstevel@tonic-gate for (i = 0; i < NDGRPS_PER_MC; i++) { 13897c478bd9Sstevel@tonic-gate dgrpid = mc_id * NDGRPS_PER_MC + i; 13907c478bd9Sstevel@tonic-gate if (!(dgrp = mc_node_get(dgrpid, dgrp_head))) { 13917c478bd9Sstevel@tonic-gate continue; 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate 13947c478bd9Sstevel@tonic-gate for (j = 0; j < NDIMMS_PER_DGRP; j++) { 13957c478bd9Sstevel@tonic-gate devid = dgrpid * NDIMMS_PER_DGRP + j; 13967c478bd9Sstevel@tonic-gate if (devp = mc_node_get(devid, device_head)) { 13977c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)devp, 13987c478bd9Sstevel@tonic-gate &device_head, &device_tail); 13997c478bd9Sstevel@tonic-gate kmem_free(devp, sizeof (*devp)); 14007c478bd9Sstevel@tonic-gate } else 14017c478bd9Sstevel@tonic-gate DPRINTF(MC_DESTRC_DEBUG, 14027c478bd9Sstevel@tonic-gate ("mc_delete: no dev %d\n", devid)); 14037c478bd9Sstevel@tonic-gate } 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)dgrp, &dgrp_head, &dgrp_tail); 14067c478bd9Sstevel@tonic-gate kmem_free(dgrp, sizeof (*dgrp)); 14077c478bd9Sstevel@tonic-gate } 14087c478bd9Sstevel@tonic-gate 14097c478bd9Sstevel@tonic-gate /* delete all banks and associated segments */ 14107c478bd9Sstevel@tonic-gate for (i = 0; i < NLOGBANKS_PER_MC; i++) { 14117c478bd9Sstevel@tonic-gate bankid = mc_id * NLOGBANKS_PER_MC + i; 14127c478bd9Sstevel@tonic-gate if (!(banki = mc_node_get(bankid, bank_head))) { 14137c478bd9Sstevel@tonic-gate continue; 14147c478bd9Sstevel@tonic-gate } 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate /* bank and segments go together */ 1417c311de31Sarutz if ((segi = mc_node_get(banki->seg_id, seg_head)) != NULL) { 14187c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)segi, &seg_head, &seg_tail); 14197c478bd9Sstevel@tonic-gate kmem_free(segi, sizeof (*segi)); 14207c478bd9Sstevel@tonic-gate nsegments--; 14217c478bd9Sstevel@tonic-gate } 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate mc_node_del((mc_dlist_t *)banki, &bank_head, &bank_tail); 14247c478bd9Sstevel@tonic-gate kmem_free(banki, sizeof (*banki)); 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 14287c478bd9Sstevel@tonic-gate } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * mc_dlist is a double linking list, including unique id, and pointers to 14327c478bd9Sstevel@tonic-gate * next, and previous nodes. seg_info, bank_info, dgrp_info, device_info, 14337c478bd9Sstevel@tonic-gate * and mctrl_info has it at the top to share the operations, add, del, and get. 14347c478bd9Sstevel@tonic-gate * 14357c478bd9Sstevel@tonic-gate * The new node is added at the tail and is not sorted. 14367c478bd9Sstevel@tonic-gate * 14377c478bd9Sstevel@tonic-gate * Input: The pointer of node to be added, head and tail of the list 14387c478bd9Sstevel@tonic-gate */ 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate static void 14417c478bd9Sstevel@tonic-gate mc_node_add(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail) 14427c478bd9Sstevel@tonic-gate { 14437c478bd9Sstevel@tonic-gate DPRINTF(MC_LIST_DEBUG, ("mc_node_add: node->id %d head %p tail %p\n", 14447c478bd9Sstevel@tonic-gate node->id, (void *) *head, (void *) *tail)); 14457c478bd9Sstevel@tonic-gate 14467c478bd9Sstevel@tonic-gate if (*head != NULL) { 14477c478bd9Sstevel@tonic-gate node->prev = *tail; 14487c478bd9Sstevel@tonic-gate node->next = (*tail)->next; 14497c478bd9Sstevel@tonic-gate (*tail)->next = node; 14507c478bd9Sstevel@tonic-gate *tail = node; 14517c478bd9Sstevel@tonic-gate } else { 14527c478bd9Sstevel@tonic-gate node->next = node->prev = NULL; 14537c478bd9Sstevel@tonic-gate *head = *tail = node; 14547c478bd9Sstevel@tonic-gate } 14557c478bd9Sstevel@tonic-gate } 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate /* 14587c478bd9Sstevel@tonic-gate * Input: The pointer of node to be deleted, head and tail of the list 14597c478bd9Sstevel@tonic-gate * 14607c478bd9Sstevel@tonic-gate * Deleted node will be at the following positions 14617c478bd9Sstevel@tonic-gate * 1. At the tail of the list 14627c478bd9Sstevel@tonic-gate * 2. At the head of the list 14637c478bd9Sstevel@tonic-gate * 3. At the head and tail of the list, i.e. only one left. 14647c478bd9Sstevel@tonic-gate * 4. At the middle of the list 14657c478bd9Sstevel@tonic-gate */ 14667c478bd9Sstevel@tonic-gate 14677c478bd9Sstevel@tonic-gate static void 14687c478bd9Sstevel@tonic-gate mc_node_del(mc_dlist_t *node, mc_dlist_t **head, mc_dlist_t **tail) 14697c478bd9Sstevel@tonic-gate { 14707c478bd9Sstevel@tonic-gate if (node->next == NULL) { 14717c478bd9Sstevel@tonic-gate /* deleted node is at the tail of list */ 14727c478bd9Sstevel@tonic-gate *tail = node->prev; 14737c478bd9Sstevel@tonic-gate } else { 14747c478bd9Sstevel@tonic-gate node->next->prev = node->prev; 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate 14777c478bd9Sstevel@tonic-gate if (node->prev == NULL) { 14787c478bd9Sstevel@tonic-gate /* deleted node is at the head of list */ 14797c478bd9Sstevel@tonic-gate *head = node->next; 14807c478bd9Sstevel@tonic-gate } else { 14817c478bd9Sstevel@tonic-gate node->prev->next = node->next; 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate 14857c478bd9Sstevel@tonic-gate /* 14867c478bd9Sstevel@tonic-gate * Search the list from the head of the list to match the given id 14877c478bd9Sstevel@tonic-gate * Input: id and the head of the list 14887c478bd9Sstevel@tonic-gate * Return: pointer of found node 14897c478bd9Sstevel@tonic-gate */ 14907c478bd9Sstevel@tonic-gate static void * 14917c478bd9Sstevel@tonic-gate mc_node_get(int id, mc_dlist_t *head) 14927c478bd9Sstevel@tonic-gate { 14937c478bd9Sstevel@tonic-gate mc_dlist_t *node; 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate node = head; 14967c478bd9Sstevel@tonic-gate while (node != NULL) { 14977c478bd9Sstevel@tonic-gate DPRINTF(MC_LIST_DEBUG, ("mc_node_get: id %d, given id %d\n", 14987c478bd9Sstevel@tonic-gate node->id, id)); 14997c478bd9Sstevel@tonic-gate if (node->id == id) 15007c478bd9Sstevel@tonic-gate break; 15017c478bd9Sstevel@tonic-gate node = node->next; 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate return (node); 15047c478bd9Sstevel@tonic-gate } 15057c478bd9Sstevel@tonic-gate 15067c478bd9Sstevel@tonic-gate /* 15077c478bd9Sstevel@tonic-gate * Memory subsystem provides 144 bits (128 Data bits, 9 ECC bits and 7 15087c478bd9Sstevel@tonic-gate * unused bits) interface via a pair of DIMMs. Mapping of Data/ECC bits 15097c478bd9Sstevel@tonic-gate * to a specific DIMM pin is described by the memory-layout property 15107c478bd9Sstevel@tonic-gate * via two tables: dimm table and pin table. 15117c478bd9Sstevel@tonic-gate * 15127c478bd9Sstevel@tonic-gate * Memory-layout property arranges data/ecc bits in the following order: 15137c478bd9Sstevel@tonic-gate * 15147c478bd9Sstevel@tonic-gate * Bit# 143 16 15 7 6 0 15157c478bd9Sstevel@tonic-gate * | Data[127:0] | ECC[8:0] | Unused[6:0] | 15167c478bd9Sstevel@tonic-gate * 15177c478bd9Sstevel@tonic-gate * dimm table: 1 bit is used to store DIMM number (2 possible DIMMs) for 15187c478bd9Sstevel@tonic-gate * each Data/ECC bit. Thus, it needs 18 bytes (144/8) to represent 15197c478bd9Sstevel@tonic-gate * all Data/ECC bits in this table. Information is stored in big 15207c478bd9Sstevel@tonic-gate * endian order, i.e. dimm_table[0] represents information for 15217c478bd9Sstevel@tonic-gate * logical bit# 143 to 136. 15227c478bd9Sstevel@tonic-gate * 15237c478bd9Sstevel@tonic-gate * pin table: 1 byte is used to store pin position for each Data/ECC bit. 15247c478bd9Sstevel@tonic-gate * Thus, this table is 144 bytes long. Information is stored in little 15257c478bd9Sstevel@tonic-gate * endian order, i.e, pin_table[0] represents pin number of logical 15267c478bd9Sstevel@tonic-gate * bit 0 and pin_table[143] contains pin number for logical bit 143 15277c478bd9Sstevel@tonic-gate * (i.e. data bit# 127). 15287c478bd9Sstevel@tonic-gate * 15297c478bd9Sstevel@tonic-gate * qwordmap table below is used to map mc_get_mem_unum "synd_code" value into 15307c478bd9Sstevel@tonic-gate * logical bit position assigned above by the memory-layout property. 15317c478bd9Sstevel@tonic-gate */ 15327c478bd9Sstevel@tonic-gate 15337c478bd9Sstevel@tonic-gate #define QWORD_SIZE 144 15347c478bd9Sstevel@tonic-gate static uint8_t qwordmap[QWORD_SIZE] = 15357c478bd9Sstevel@tonic-gate { 15367c478bd9Sstevel@tonic-gate 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 15377c478bd9Sstevel@tonic-gate 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 15387c478bd9Sstevel@tonic-gate 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 15397c478bd9Sstevel@tonic-gate 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 15407c478bd9Sstevel@tonic-gate 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 15417c478bd9Sstevel@tonic-gate 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 15427c478bd9Sstevel@tonic-gate 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 15437c478bd9Sstevel@tonic-gate 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 15447c478bd9Sstevel@tonic-gate 7, 8, 9, 10, 11, 12, 13, 14, 15, 4, 5, 6, 0, 1, 2, 3 15457c478bd9Sstevel@tonic-gate }; 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate 15487c478bd9Sstevel@tonic-gate /* ARGSUSED */ 15497c478bd9Sstevel@tonic-gate static int 15507c478bd9Sstevel@tonic-gate mc_get_mem_unum(int synd_code, uint64_t paddr, char *buf, int buflen, int *lenp) 15517c478bd9Sstevel@tonic-gate { 15527c478bd9Sstevel@tonic-gate int i; 15537c478bd9Sstevel@tonic-gate int pos_cacheline, position, index, idx4dimm; 15547c478bd9Sstevel@tonic-gate int qwlayout = synd_code; 15557c478bd9Sstevel@tonic-gate short offset, data; 15567c478bd9Sstevel@tonic-gate char unum[UNUM_NAMLEN]; 15577c478bd9Sstevel@tonic-gate struct dimm_info *dimmp; 15587c478bd9Sstevel@tonic-gate struct pin_info *pinp; 15597c478bd9Sstevel@tonic-gate struct bank_info *bank; 15607c478bd9Sstevel@tonic-gate struct mctrl_info *mctrl; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate /* 15637c478bd9Sstevel@tonic-gate * Enforce old Openboot requirement for synd code, either a single-bit 15647c478bd9Sstevel@tonic-gate * code from 0..QWORD_SIZE-1 or -1 (multi-bit error). 15657c478bd9Sstevel@tonic-gate */ 15667c478bd9Sstevel@tonic-gate if (qwlayout < -1 || qwlayout >= QWORD_SIZE) 15677c478bd9Sstevel@tonic-gate return (EINVAL); 15687c478bd9Sstevel@tonic-gate 15697c478bd9Sstevel@tonic-gate unum[0] = '\0'; 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate DPRINTF(MC_GUNUM_DEBUG, ("mc_get_mem_unum:qwlayout %d phyaddr 0x%lx\n", 15727c478bd9Sstevel@tonic-gate qwlayout, paddr)); 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate /* 15757c478bd9Sstevel@tonic-gate * Scan all logical banks to get one responding to the physical 15767c478bd9Sstevel@tonic-gate * address. Then compute the index to look up dimm and pin tables 15777c478bd9Sstevel@tonic-gate * to generate the unmuber. 15787c478bd9Sstevel@tonic-gate */ 15797c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 15807c478bd9Sstevel@tonic-gate bank = (struct bank_info *)bank_head; 15817c478bd9Sstevel@tonic-gate while (bank != NULL) { 15827c478bd9Sstevel@tonic-gate int mcid, mcdgrpid, dimmoffset; 15837c478bd9Sstevel@tonic-gate 15847c478bd9Sstevel@tonic-gate /* 15857c478bd9Sstevel@tonic-gate * Physical Address is in a bank if (Addr & Mask) == Match 15867c478bd9Sstevel@tonic-gate */ 15877c478bd9Sstevel@tonic-gate if ((paddr & bank->mask) != bank->match) { 15887c478bd9Sstevel@tonic-gate bank = (struct bank_info *)bank->bank_node.next; 15897c478bd9Sstevel@tonic-gate continue; 15907c478bd9Sstevel@tonic-gate } 15917c478bd9Sstevel@tonic-gate 15927c478bd9Sstevel@tonic-gate mcid = bank->bank_node.id / NLOGBANKS_PER_MC; 15937c478bd9Sstevel@tonic-gate mctrl = mc_node_get(mcid, mctrl_head); 15947c478bd9Sstevel@tonic-gate ASSERT(mctrl != NULL); 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate DPRINTF(MC_GUNUM_DEBUG, ("mc_get_mem_unum:mc %d bank %d " 15977c478bd9Sstevel@tonic-gate "dgrp %d\n", mcid, bank->bank_node.id, bank->devgrp_id)); 15987c478bd9Sstevel@tonic-gate 15997c478bd9Sstevel@tonic-gate mcdgrpid = bank->devgrp_id % NDGRPS_PER_MC; 16007c478bd9Sstevel@tonic-gate dimmoffset = mcdgrpid * NDIMMS_PER_DGRP; 16017c478bd9Sstevel@tonic-gate 16027c478bd9Sstevel@tonic-gate dimmp = (struct dimm_info *)mctrl->dimminfop; 16037c478bd9Sstevel@tonic-gate if (dimmp == NULL) { 16047c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 16057c478bd9Sstevel@tonic-gate return (ENXIO); 16067c478bd9Sstevel@tonic-gate } 16077c478bd9Sstevel@tonic-gate 16087c478bd9Sstevel@tonic-gate if ((qwlayout >= 0) && (qwlayout < QWORD_SIZE)) { 16097c478bd9Sstevel@tonic-gate /* 16107c478bd9Sstevel@tonic-gate * single-bit error handling, we can identify specific 16117c478bd9Sstevel@tonic-gate * DIMM. 16127c478bd9Sstevel@tonic-gate */ 16137c478bd9Sstevel@tonic-gate 16147c478bd9Sstevel@tonic-gate pinp = (struct pin_info *)&dimmp->data[0]; 16157c478bd9Sstevel@tonic-gate 16167c478bd9Sstevel@tonic-gate pos_cacheline = qwordmap[qwlayout]; 16177c478bd9Sstevel@tonic-gate position = 143 - pos_cacheline; 16187c478bd9Sstevel@tonic-gate index = position / 8; 16197c478bd9Sstevel@tonic-gate offset = 7 - (position % 8); 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate DPRINTF(MC_GUNUM_DEBUG, ("mc_get_mem_unum:position " 16227c478bd9Sstevel@tonic-gate "%d\n", position)); 16237c478bd9Sstevel@tonic-gate /* 16247c478bd9Sstevel@tonic-gate * Trade-off: We cound't add pin number to 16257c478bd9Sstevel@tonic-gate * unumber string because statistic number 16267c478bd9Sstevel@tonic-gate * pumps up at the corresponding dimm not pin. 16277c478bd9Sstevel@tonic-gate * (void) sprintf(unum, "Pin %1u ", (uint_t) 16287c478bd9Sstevel@tonic-gate * pinp->pintable[pos_cacheline]); 16297c478bd9Sstevel@tonic-gate */ 16307c478bd9Sstevel@tonic-gate DPRINTF(MC_GUNUM_DEBUG, ("mc_get_mem_unum:pin number " 16317c478bd9Sstevel@tonic-gate "%1u\n", (uint_t)pinp->pintable[pos_cacheline])); 16327c478bd9Sstevel@tonic-gate data = pinp->dimmtable[index]; 16337c478bd9Sstevel@tonic-gate idx4dimm = (data >> offset) & 1; 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate (void) strncpy(unum, 16367c478bd9Sstevel@tonic-gate (char *)dimmp->label[dimmoffset + idx4dimm], 16377c478bd9Sstevel@tonic-gate UNUM_NAMLEN); 16387c478bd9Sstevel@tonic-gate 16397c478bd9Sstevel@tonic-gate DPRINTF(MC_GUNUM_DEBUG, 16407c478bd9Sstevel@tonic-gate ("mc_get_mem_unum:unum %s\n", unum)); 16417c478bd9Sstevel@tonic-gate 16427c478bd9Sstevel@tonic-gate /* 16437c478bd9Sstevel@tonic-gate * platform hook for adding label information to unum. 16447c478bd9Sstevel@tonic-gate */ 16457c478bd9Sstevel@tonic-gate mc_add_mem_unum_label(unum, mcid, mcdgrpid, idx4dimm); 16467c478bd9Sstevel@tonic-gate } else { 16477c478bd9Sstevel@tonic-gate char *p = unum; 16487c478bd9Sstevel@tonic-gate size_t res = UNUM_NAMLEN; 16497c478bd9Sstevel@tonic-gate 16507c478bd9Sstevel@tonic-gate /* 16517c478bd9Sstevel@tonic-gate * multi-bit error handling, we can only identify 16527c478bd9Sstevel@tonic-gate * bank of DIMMs. 16537c478bd9Sstevel@tonic-gate */ 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate for (i = 0; (i < NDIMMS_PER_DGRP) && (res > 0); i++) { 16567c478bd9Sstevel@tonic-gate (void) snprintf(p, res, "%s%s", 16577c478bd9Sstevel@tonic-gate i == 0 ? "" : " ", 16587c478bd9Sstevel@tonic-gate (char *)dimmp->label[dimmoffset + i]); 16597c478bd9Sstevel@tonic-gate res -= strlen(p); 16607c478bd9Sstevel@tonic-gate p += strlen(p); 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate /* 16647c478bd9Sstevel@tonic-gate * platform hook for adding label information 16657c478bd9Sstevel@tonic-gate * to unum. 16667c478bd9Sstevel@tonic-gate */ 16677c478bd9Sstevel@tonic-gate mc_add_mem_unum_label(unum, mcid, mcdgrpid, -1); 16687c478bd9Sstevel@tonic-gate } 16697c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 16707c478bd9Sstevel@tonic-gate if ((strlen(unum) >= UNUM_NAMLEN) || 16717c478bd9Sstevel@tonic-gate (strlen(unum) >= buflen)) { 16726684e119Spothier return (ENAMETOOLONG); 16737c478bd9Sstevel@tonic-gate } else { 16747c478bd9Sstevel@tonic-gate (void) strncpy(buf, unum, UNUM_NAMLEN); 16757c478bd9Sstevel@tonic-gate *lenp = strlen(buf); 16767c478bd9Sstevel@tonic-gate return (0); 16777c478bd9Sstevel@tonic-gate } 16787c478bd9Sstevel@tonic-gate } /* end of while loop for logic bank list */ 16797c478bd9Sstevel@tonic-gate 16807c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 16817c478bd9Sstevel@tonic-gate return (ENXIO); 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate 16847c478bd9Sstevel@tonic-gate static int 16857c478bd9Sstevel@tonic-gate mc_get_mem_info(int synd_code, uint64_t paddr, 16867c478bd9Sstevel@tonic-gate uint64_t *mem_sizep, uint64_t *seg_sizep, uint64_t *bank_sizep, 16877c478bd9Sstevel@tonic-gate int *segsp, int *banksp, int *mcidp) 16887c478bd9Sstevel@tonic-gate { 16897c478bd9Sstevel@tonic-gate struct bank_info *bankp; 16907c478bd9Sstevel@tonic-gate 16917c478bd9Sstevel@tonic-gate if (synd_code < -1 || synd_code >= QWORD_SIZE) 16927c478bd9Sstevel@tonic-gate return (EINVAL); 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate /* 16957c478bd9Sstevel@tonic-gate * Scan all logical banks to get one responding to the physical 16967c478bd9Sstevel@tonic-gate * address. Then compute the index to look up dimm and pin tables 16977c478bd9Sstevel@tonic-gate * to generate the unmuber. 16987c478bd9Sstevel@tonic-gate */ 16997c478bd9Sstevel@tonic-gate mutex_enter(&mcdatamutex); 17007c478bd9Sstevel@tonic-gate bankp = (struct bank_info *)bank_head; 17017c478bd9Sstevel@tonic-gate while (bankp != NULL) { 17027c478bd9Sstevel@tonic-gate struct seg_info *segp; 17037c478bd9Sstevel@tonic-gate int mcid; 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate /* 17067c478bd9Sstevel@tonic-gate * Physical Address is in a bank if (Addr & Mask) == Match 17077c478bd9Sstevel@tonic-gate */ 17087c478bd9Sstevel@tonic-gate if ((paddr & bankp->mask) != bankp->match) { 17097c478bd9Sstevel@tonic-gate bankp = (struct bank_info *)bankp->bank_node.next; 17107c478bd9Sstevel@tonic-gate continue; 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate 17137c478bd9Sstevel@tonic-gate mcid = bankp->bank_node.id / NLOGBANKS_PER_MC; 17147c478bd9Sstevel@tonic-gate 17157c478bd9Sstevel@tonic-gate /* 17167c478bd9Sstevel@tonic-gate * Get the corresponding segment. 17177c478bd9Sstevel@tonic-gate */ 17187c478bd9Sstevel@tonic-gate if ((segp = (struct seg_info *)mc_node_get(bankp->seg_id, 17197c478bd9Sstevel@tonic-gate seg_head)) == NULL) { 17207c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 17217c478bd9Sstevel@tonic-gate return (EFAULT); 17227c478bd9Sstevel@tonic-gate } 17237c478bd9Sstevel@tonic-gate 17247c478bd9Sstevel@tonic-gate *mem_sizep = memsize; 17257c478bd9Sstevel@tonic-gate *seg_sizep = segp->size; 17267c478bd9Sstevel@tonic-gate *bank_sizep = bankp->size; 17277c478bd9Sstevel@tonic-gate *segsp = nsegments; 17287c478bd9Sstevel@tonic-gate *banksp = segp->nbanks; 17297c478bd9Sstevel@tonic-gate *mcidp = mcid; 17307c478bd9Sstevel@tonic-gate 17317c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 17327c478bd9Sstevel@tonic-gate return (0); 17337c478bd9Sstevel@tonic-gate 17347c478bd9Sstevel@tonic-gate } /* end of while loop for logic bank list */ 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate mutex_exit(&mcdatamutex); 17377c478bd9Sstevel@tonic-gate return (ENXIO); 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate /* 17407c478bd9Sstevel@tonic-gate * mc-us3i driver allows a platform to add extra label 17417c478bd9Sstevel@tonic-gate * information to the unum string. If a platform implements a 17427c478bd9Sstevel@tonic-gate * kernel function called plat_add_mem_unum_label() it will be 17437c478bd9Sstevel@tonic-gate * executed. This would typically be implemented in the platmod. 17447c478bd9Sstevel@tonic-gate */ 17457c478bd9Sstevel@tonic-gate static void 17467c478bd9Sstevel@tonic-gate mc_add_mem_unum_label(char *unum, int mcid, int bank, int dimm) 17477c478bd9Sstevel@tonic-gate { 17487c478bd9Sstevel@tonic-gate if (&plat_add_mem_unum_label) 17497c478bd9Sstevel@tonic-gate plat_add_mem_unum_label(unum, mcid, bank, dimm); 17507c478bd9Sstevel@tonic-gate } 1751