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