xref: /illumos-gate/usr/src/uts/sun4u/opl/io/mc-opl.c (revision bbe1232e)
125cf1a30Sjl /*
225cf1a30Sjl  * CDDL HEADER START
325cf1a30Sjl  *
425cf1a30Sjl  * The contents of this file are subject to the terms of the
525cf1a30Sjl  * Common Development and Distribution License (the "License").
625cf1a30Sjl  * You may not use this file except in compliance with the License.
725cf1a30Sjl  *
825cf1a30Sjl  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925cf1a30Sjl  * or http://www.opensolaris.org/os/licensing.
1025cf1a30Sjl  * See the License for the specific language governing permissions
1125cf1a30Sjl  * and limitations under the License.
1225cf1a30Sjl  *
1325cf1a30Sjl  * When distributing Covered Code, include this CDDL HEADER in each
1425cf1a30Sjl  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525cf1a30Sjl  * If applicable, add the following below this CDDL HEADER, with the
1625cf1a30Sjl  * fields enclosed by brackets "[]" replaced with your own identifying
1725cf1a30Sjl  * information: Portions Copyright [yyyy] [name of copyright owner]
1825cf1a30Sjl  *
1925cf1a30Sjl  * CDDL HEADER END
2025cf1a30Sjl  */
211e2e7a75Shuah /*
22392e836bSGavin Maltby  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
231e2e7a75Shuah  */
2425cf1a30Sjl /*
2578ed97a7Sjl  * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2008
2625cf1a30Sjl  */
2725cf1a30Sjl 
2825cf1a30Sjl #include <sys/types.h>
2925cf1a30Sjl #include <sys/sysmacros.h>
3025cf1a30Sjl #include <sys/conf.h>
3125cf1a30Sjl #include <sys/modctl.h>
3225cf1a30Sjl #include <sys/stat.h>
3325cf1a30Sjl #include <sys/async.h>
341e2e7a75Shuah #include <sys/machcpuvar.h>
3525cf1a30Sjl #include <sys/machsystm.h>
360cc8ae86Sav #include <sys/promif.h>
3725cf1a30Sjl #include <sys/ksynch.h>
3825cf1a30Sjl #include <sys/ddi.h>
3925cf1a30Sjl #include <sys/sunddi.h>
40d8a0cca9Swh #include <sys/sunndi.h>
4125cf1a30Sjl #include <sys/ddifm.h>
4225cf1a30Sjl #include <sys/fm/protocol.h>
4325cf1a30Sjl #include <sys/fm/util.h>
4425cf1a30Sjl #include <sys/kmem.h>
4525cf1a30Sjl #include <sys/fm/io/opl_mc_fm.h>
4625cf1a30Sjl #include <sys/memlist.h>
4725cf1a30Sjl #include <sys/param.h>
480cc8ae86Sav #include <sys/disp.h>
4925cf1a30Sjl #include <vm/page.h>
5025cf1a30Sjl #include <sys/mc-opl.h>
510cc8ae86Sav #include <sys/opl.h>
520cc8ae86Sav #include <sys/opl_dimm.h>
530cc8ae86Sav #include <sys/scfd/scfostoescf.h>
54cfb9e062Shyw #include <sys/cpu_module.h>
55cfb9e062Shyw #include <vm/seg_kmem.h>
56cfb9e062Shyw #include <sys/vmem.h>
57cfb9e062Shyw #include <vm/hat_sfmmu.h>
58cfb9e062Shyw #include <sys/vmsystm.h>
59738dd194Shyw #include <sys/membar.h>
600b240fcdSwh #include <sys/mem.h>
6125cf1a30Sjl 
6225cf1a30Sjl /*
6325cf1a30Sjl  * Function prototypes
6425cf1a30Sjl  */
6525cf1a30Sjl static int mc_open(dev_t *, int, int, cred_t *);
6625cf1a30Sjl static int mc_close(dev_t, int, int, cred_t *);
6725cf1a30Sjl static int mc_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
6825cf1a30Sjl static int mc_attach(dev_info_t *, ddi_attach_cmd_t);
6925cf1a30Sjl static int mc_detach(dev_info_t *, ddi_detach_cmd_t);
7025cf1a30Sjl 
710cc8ae86Sav static int mc_poll_init(void);
720cc8ae86Sav static void mc_poll_fini(void);
7325cf1a30Sjl static int mc_board_add(mc_opl_t *mcp);
7425cf1a30Sjl static int mc_board_del(mc_opl_t *mcp);
7525cf1a30Sjl static int mc_suspend(mc_opl_t *mcp, uint32_t flag);
7625cf1a30Sjl static int mc_resume(mc_opl_t *mcp, uint32_t flag);
770cc8ae86Sav int opl_mc_suspend(void);
780cc8ae86Sav int opl_mc_resume(void);
7925cf1a30Sjl 
8025cf1a30Sjl static void insert_mcp(mc_opl_t *mcp);
8125cf1a30Sjl static void delete_mcp(mc_opl_t *mcp);
8225cf1a30Sjl 
8325cf1a30Sjl static int pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr);
8425cf1a30Sjl 
85738dd194Shyw static int mc_rangecheck_pa(mc_opl_t *mcp, uint64_t pa);
8625cf1a30Sjl 
8725cf1a30Sjl int mc_get_mem_unum(int, uint64_t, char *, int, int *);
880cc8ae86Sav int mc_get_mem_addr(char *unum, char *sid, uint64_t offset, uint64_t *paddr);
890cc8ae86Sav int mc_get_mem_offset(uint64_t paddr, uint64_t *offp);
900cc8ae86Sav int mc_get_mem_sid(char *unum, char *buf, int buflen, int *lenp);
910cc8ae86Sav int mc_get_mem_sid_dimm(mc_opl_t *mcp, char *dname, char *buf,
920cc8ae86Sav     int buflen, int *lenp);
930cc8ae86Sav mc_dimm_info_t *mc_get_dimm_list(mc_opl_t *mcp);
940cc8ae86Sav mc_dimm_info_t *mc_prepare_dimmlist(board_dimm_info_t *bd_dimmp);
950cc8ae86Sav int mc_set_mem_sid(mc_opl_t *mcp, char *buf, int buflen, int lsb, int bank,
960cc8ae86Sav     uint32_t mf_type, uint32_t d_slot);
970cc8ae86Sav static void mc_free_dimm_list(mc_dimm_info_t *d);
9825cf1a30Sjl static void mc_get_mlist(mc_opl_t *);
990cc8ae86Sav static void mc_polling(void);
1000cc8ae86Sav static int mc_opl_get_physical_board(int);
1010cc8ae86Sav 
102601c2e1eSdhain static void mc_clear_rewrite(mc_opl_t *mcp, int i);
103601c2e1eSdhain static void mc_set_rewrite(mc_opl_t *mcp, int bank, uint32_t addr, int state);
1040b240fcdSwh static int mc_scf_log_event(mc_flt_page_t *flt_pag);
105601c2e1eSdhain 
1060cc8ae86Sav #ifdef	DEBUG
1070cc8ae86Sav static int mc_ioctl_debug(dev_t, int, intptr_t, int, cred_t *, int *);
1080cc8ae86Sav void mc_dump_dimm(char *buf, int dnamesz, int serialsz, int partnumsz);
1090cc8ae86Sav void mc_dump_dimm_info(board_dimm_info_t *bd_dimmp);
1100cc8ae86Sav #endif
11125cf1a30Sjl 
11225cf1a30Sjl #pragma weak opl_get_physical_board
11325cf1a30Sjl extern int opl_get_physical_board(int);
1140cc8ae86Sav extern int plat_max_boards(void);
11525cf1a30Sjl 
11625cf1a30Sjl /*
11725cf1a30Sjl  * Configuration data structures
11825cf1a30Sjl  */
11925cf1a30Sjl static struct cb_ops mc_cb_ops = {
12025cf1a30Sjl 	mc_open,			/* open */
12125cf1a30Sjl 	mc_close,			/* close */
12225cf1a30Sjl 	nulldev,			/* strategy */
12325cf1a30Sjl 	nulldev,			/* print */
12425cf1a30Sjl 	nodev,				/* dump */
12525cf1a30Sjl 	nulldev,			/* read */
12625cf1a30Sjl 	nulldev,			/* write */
12725cf1a30Sjl 	mc_ioctl,			/* ioctl */
12825cf1a30Sjl 	nodev,				/* devmap */
12925cf1a30Sjl 	nodev,				/* mmap */
13025cf1a30Sjl 	nodev,				/* segmap */
13125cf1a30Sjl 	nochpoll,			/* poll */
13225cf1a30Sjl 	ddi_prop_op,			/* cb_prop_op */
13325cf1a30Sjl 	0,				/* streamtab */
13425cf1a30Sjl 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
13525cf1a30Sjl 	CB_REV,				/* rev */
13625cf1a30Sjl 	nodev,				/* cb_aread */
13725cf1a30Sjl 	nodev				/* cb_awrite */
13825cf1a30Sjl };
13925cf1a30Sjl 
14025cf1a30Sjl static struct dev_ops mc_ops = {
14125cf1a30Sjl 	DEVO_REV,			/* rev */
14225cf1a30Sjl 	0,				/* refcnt  */
14325cf1a30Sjl 	ddi_getinfo_1to1,		/* getinfo */
14425cf1a30Sjl 	nulldev,			/* identify */
14525cf1a30Sjl 	nulldev,			/* probe */
14625cf1a30Sjl 	mc_attach,			/* attach */
14725cf1a30Sjl 	mc_detach,			/* detach */
14825cf1a30Sjl 	nulldev,			/* reset */
14925cf1a30Sjl 	&mc_cb_ops,			/* cb_ops */
15025cf1a30Sjl 	(struct bus_ops *)0,		/* bus_ops */
15119397407SSherry Moore 	nulldev,			/* power */
15219397407SSherry Moore 	ddi_quiesce_not_needed,			/* quiesce */
15325cf1a30Sjl };
15425cf1a30Sjl 
15525cf1a30Sjl /*
15625cf1a30Sjl  * Driver globals
15725cf1a30Sjl  */
15825cf1a30Sjl 
1590cc8ae86Sav static enum {
16078ed97a7Sjl 	MODEL_FF1,
16178ed97a7Sjl 	MODEL_FF2,
16278ed97a7Sjl 	MODEL_DC,
16378ed97a7Sjl 	MODEL_IKKAKU
1640cc8ae86Sav } plat_model = MODEL_DC;	/* The default behaviour is DC */
1650cc8ae86Sav 
1660cc8ae86Sav static struct plat_model_names {
1670cc8ae86Sav 	const char *unit_name;
1680cc8ae86Sav 	const char *mem_name;
1690cc8ae86Sav } model_names[] = {
1700cc8ae86Sav 	{ "MBU_A", "MEMB" },
1710cc8ae86Sav 	{ "MBU_B", "MEMB" },
17278ed97a7Sjl 	{ "CMU", "" },
17378ed97a7Sjl 	{ "MBU_A", "" }
1740cc8ae86Sav };
17525cf1a30Sjl 
1760cc8ae86Sav /*
1770cc8ae86Sav  * The DIMM Names for DC platform.
1780cc8ae86Sav  * The index into this table is made up of (bank, dslot),
1790cc8ae86Sav  * Where dslot occupies bits 0-1 and bank occupies 2-4.
1800cc8ae86Sav  */
1810cc8ae86Sav static char *mc_dc_dimm_unum_table[OPL_MAX_DIMMS] = {
1820cc8ae86Sav 	/* --------CMUnn----------- */
1830cc8ae86Sav 	/* --CS0-----|--CS1------ */
1840cc8ae86Sav 	/* -H-|--L-- | -H- | -L-- */
185c964b0e6Sraghuram 	"03A", "02A", "03B", "02B", /* Bank 0 (MAC 0 bank 0) */
186c964b0e6Sraghuram 	"13A", "12A", "13B", "12B", /* Bank 1 (MAC 0 bank 1) */
187c964b0e6Sraghuram 	"23A", "22A", "23B", "22B", /* Bank 2 (MAC 1 bank 0) */
188c964b0e6Sraghuram 	"33A", "32A", "33B", "32B", /* Bank 3 (MAC 1 bank 1) */
189c964b0e6Sraghuram 	"01A", "00A", "01B", "00B", /* Bank 4 (MAC 2 bank 0) */
190c964b0e6Sraghuram 	"11A", "10A", "11B", "10B", /* Bank 5 (MAC 2 bank 1) */
191c964b0e6Sraghuram 	"21A", "20A", "21B", "20B", /* Bank 6 (MAC 3 bank 0) */
192c964b0e6Sraghuram 	"31A", "30A", "31B", "30B"  /* Bank 7 (MAC 3 bank 1) */
1930cc8ae86Sav };
1940cc8ae86Sav 
1950cc8ae86Sav /*
19678ed97a7Sjl  * The DIMM Names for FF1/FF2/IKKAKU platforms.
1970cc8ae86Sav  * The index into this table is made up of (board, bank, dslot),
1980cc8ae86Sav  * Where dslot occupies bits 0-1, bank occupies 2-4 and
1990cc8ae86Sav  * board occupies the bit 5.
2000cc8ae86Sav  */
2010cc8ae86Sav static char *mc_ff_dimm_unum_table[2 * OPL_MAX_DIMMS] = {
2020cc8ae86Sav 	/* --------CMU0---------- */
2030cc8ae86Sav 	/* --CS0-----|--CS1------ */
2040cc8ae86Sav 	/* -H-|--L-- | -H- | -L-- */
205c964b0e6Sraghuram 	"03A", "02A", "03B", "02B", /* Bank 0 (MAC 0 bank 0) */
206c964b0e6Sraghuram 	"01A", "00A", "01B", "00B", /* Bank 1 (MAC 0 bank 1) */
207c964b0e6Sraghuram 	"13A", "12A", "13B", "12B", /* Bank 2 (MAC 1 bank 0) */
208c964b0e6Sraghuram 	"11A", "10A", "11B", "10B", /* Bank 3 (MAC 1 bank 1) */
209c964b0e6Sraghuram 	"23A", "22A", "23B", "22B", /* Bank 4 (MAC 2 bank 0) */
210c964b0e6Sraghuram 	"21A", "20A", "21B", "20B", /* Bank 5 (MAC 2 bank 1) */
211c964b0e6Sraghuram 	"33A", "32A", "33B", "32B", /* Bank 6 (MAC 3 bank 0) */
212c964b0e6Sraghuram 	"31A", "30A", "31B", "30B", /* Bank 7 (MAC 3 bank 1) */
2130cc8ae86Sav 	/* --------CMU1---------- */
2140cc8ae86Sav 	/* --CS0-----|--CS1------ */
2150cc8ae86Sav 	/* -H-|--L-- | -H- | -L-- */
216c964b0e6Sraghuram 	"43A", "42A", "43B", "42B", /* Bank 0 (MAC 0 bank 0) */
217c964b0e6Sraghuram 	"41A", "40A", "41B", "40B", /* Bank 1 (MAC 0 bank 1) */
218c964b0e6Sraghuram 	"53A", "52A", "53B", "52B", /* Bank 2 (MAC 1 bank 0) */
219c964b0e6Sraghuram 	"51A", "50A", "51B", "50B", /* Bank 3 (MAC 1 bank 1) */
220c964b0e6Sraghuram 	"63A", "62A", "63B", "62B", /* Bank 4 (MAC 2 bank 0) */
221c964b0e6Sraghuram 	"61A", "60A", "61B", "60B", /* Bank 5 (MAC 2 bank 1) */
222c964b0e6Sraghuram 	"73A", "72A", "73B", "72B", /* Bank 6 (MAC 3 bank 0) */
223c964b0e6Sraghuram 	"71A", "70A", "71B", "70B"  /* Bank 7 (MAC 3 bank 1) */
2240cc8ae86Sav };
2250cc8ae86Sav 
2260cc8ae86Sav #define	BD_BK_SLOT_TO_INDEX(bd, bk, s)			\
2270cc8ae86Sav 	(((bd & 0x01) << 5) | ((bk & 0x07) << 2) | (s & 0x03))
2280cc8ae86Sav 
2290cc8ae86Sav #define	INDEX_TO_BANK(i)			(((i) & 0x1C) >> 2)
2300cc8ae86Sav #define	INDEX_TO_SLOT(i)			((i) & 0x03)
2310cc8ae86Sav 
232aeb241b2Sav #define	SLOT_TO_CS(slot)	((slot & 0x3) >> 1)
233aeb241b2Sav 
2340cc8ae86Sav /* Isolation unit size is 64 MB */
2350cc8ae86Sav #define	MC_ISOLATION_BSIZE	(64 * 1024 * 1024)
2360cc8ae86Sav 
2370cc8ae86Sav #define	MC_MAX_SPEEDS 7
2380cc8ae86Sav 
2390cc8ae86Sav typedef struct {
2400cc8ae86Sav 	uint32_t mc_speeds;
2410cc8ae86Sav 	uint32_t mc_period;
2420cc8ae86Sav } mc_scan_speed_t;
2430cc8ae86Sav 
2440cc8ae86Sav #define	MC_CNTL_SPEED_SHIFT 26
2450cc8ae86Sav 
24637afe445Shyw /*
24737afe445Shyw  * In mirror mode, we normalized the bank idx to "even" since
24837afe445Shyw  * the HW treats them as one unit w.r.t programming.
24937afe445Shyw  * This bank index will be the "effective" bank index.
25037afe445Shyw  * All mirrored bank state info on mc_period, mc_speedup_period
25137afe445Shyw  * will be stored in the even bank structure to avoid code duplication.
25237afe445Shyw  */
25337afe445Shyw #define	MIRROR_IDX(bankidx)	(bankidx & ~1)
25437afe445Shyw 
2550cc8ae86Sav static mc_scan_speed_t	mc_scan_speeds[MC_MAX_SPEEDS] = {
2560cc8ae86Sav 	{0x6 << MC_CNTL_SPEED_SHIFT, 0},
2570cc8ae86Sav 	{0x5 << MC_CNTL_SPEED_SHIFT, 32},
2580cc8ae86Sav 	{0x4 << MC_CNTL_SPEED_SHIFT, 64},
2590cc8ae86Sav 	{0x3 << MC_CNTL_SPEED_SHIFT, 128},
2600cc8ae86Sav 	{0x2 << MC_CNTL_SPEED_SHIFT, 256},
2610cc8ae86Sav 	{0x1 << MC_CNTL_SPEED_SHIFT, 512},
2620cc8ae86Sav 	{0x0 << MC_CNTL_SPEED_SHIFT, 1024}
2630cc8ae86Sav };
2640cc8ae86Sav 
2650cc8ae86Sav static uint32_t	mc_max_speed = (0x6 << 26);
2660cc8ae86Sav 
2670cc8ae86Sav int mc_isolation_bsize = MC_ISOLATION_BSIZE;
2680cc8ae86Sav int mc_patrol_interval_sec = MC_PATROL_INTERVAL_SEC;
2690cc8ae86Sav int mc_max_scf_retry = 16;
2700cc8ae86Sav int mc_max_scf_logs = 64;
2710cc8ae86Sav int mc_max_errlog_processed = BANKNUM_PER_SB*2;
2720cc8ae86Sav int mc_scan_period = 12 * 60 * 60;	/* 12 hours period */
2730cc8ae86Sav int mc_max_rewrite_loop = 100;
2740cc8ae86Sav int mc_rewrite_delay = 10;
2750cc8ae86Sav /*
2760cc8ae86Sav  * it takes SCF about 300 m.s. to process a requst.  We can bail out
2770cc8ae86Sav  * if it is busy.  It does not pay to wait for it too long.
2780cc8ae86Sav  */
2790cc8ae86Sav int mc_max_scf_loop = 2;
2800cc8ae86Sav int mc_scf_delay = 100;
2810cc8ae86Sav int mc_pce_dropped = 0;
2820cc8ae86Sav int mc_poll_priority = MINCLSYSPRI;
283601c2e1eSdhain int mc_max_rewrite_retry = 6 * 60;
28425cf1a30Sjl 
2850cc8ae86Sav 
2860cc8ae86Sav /*
2871039f409Sav  * Mutex hierarchy in mc-opl
2880cc8ae86Sav  * If both mcmutex and mc_lock must be held,
2890cc8ae86Sav  * mcmutex must be acquired first, and then mc_lock.
2900cc8ae86Sav  */
2910cc8ae86Sav 
2920cc8ae86Sav static kmutex_t mcmutex;
2930cc8ae86Sav mc_opl_t *mc_instances[OPL_MAX_BOARDS];
2940cc8ae86Sav 
2950cc8ae86Sav static kmutex_t mc_polling_lock;
2960cc8ae86Sav static kcondvar_t mc_polling_cv;
2970cc8ae86Sav static kcondvar_t mc_poll_exit_cv;
2980cc8ae86Sav static int mc_poll_cmd = 0;
2990cc8ae86Sav static int mc_pollthr_running = 0;
3000cc8ae86Sav int mc_timeout_period = 0; /* this is in m.s. */
30125cf1a30Sjl void *mc_statep;
30225cf1a30Sjl 
30325cf1a30Sjl #ifdef	DEBUG
3042742aa22Shyw int oplmc_debug = 0;
30525cf1a30Sjl #endif
30625cf1a30Sjl 
3070cc8ae86Sav static int mc_debug_show_all = 0;
30825cf1a30Sjl 
30925cf1a30Sjl extern struct mod_ops mod_driverops;
31025cf1a30Sjl 
31125cf1a30Sjl static struct modldrv modldrv = {
31225cf1a30Sjl 	&mod_driverops,			/* module type, this one is a driver */
31319397407SSherry Moore 	"OPL Memory-controller",	/* module name */
31425cf1a30Sjl 	&mc_ops,			/* driver ops */
31525cf1a30Sjl };
31625cf1a30Sjl 
31725cf1a30Sjl static struct modlinkage modlinkage = {
31825cf1a30Sjl 	MODREV_1,		/* rev */
31925cf1a30Sjl 	(void *)&modldrv,
32025cf1a30Sjl 	NULL
32125cf1a30Sjl };
32225cf1a30Sjl 
32325cf1a30Sjl #pragma weak opl_get_mem_unum
3240cc8ae86Sav #pragma weak opl_get_mem_sid
3250cc8ae86Sav #pragma weak opl_get_mem_offset
3260cc8ae86Sav #pragma weak opl_get_mem_addr
3270cc8ae86Sav 
32825cf1a30Sjl extern int (*opl_get_mem_unum)(int, uint64_t, char *, int, int *);
3290cc8ae86Sav extern int (*opl_get_mem_sid)(char *unum, char *buf, int buflen, int *lenp);
3300cc8ae86Sav extern int (*opl_get_mem_offset)(uint64_t paddr, uint64_t *offp);
3310cc8ae86Sav extern int (*opl_get_mem_addr)(char *unum, char *sid, uint64_t offset,
3320cc8ae86Sav     uint64_t *paddr);
3330cc8ae86Sav 
33425cf1a30Sjl 
33525cf1a30Sjl /*
33625cf1a30Sjl  * pseudo-mc node portid format
33725cf1a30Sjl  *
33825cf1a30Sjl  *		[10]   = 0
33925cf1a30Sjl  *		[9]    = 1
34025cf1a30Sjl  *		[8]    = LSB_ID[4] = 0
34125cf1a30Sjl  *		[7:4]  = LSB_ID[3:0]
34225cf1a30Sjl  *		[3:0]  = 0
34325cf1a30Sjl  *
34425cf1a30Sjl  */
34525cf1a30Sjl 
34625cf1a30Sjl /*
34725cf1a30Sjl  * These are the module initialization routines.
34825cf1a30Sjl  */
34925cf1a30Sjl int
_init(void)35025cf1a30Sjl _init(void)
35125cf1a30Sjl {
3520cc8ae86Sav 	int	error;
3530cc8ae86Sav 	int	plen;
3540cc8ae86Sav 	char	model[20];
3550cc8ae86Sav 	pnode_t	node;
35625cf1a30Sjl 
35725cf1a30Sjl 
35825cf1a30Sjl 	if ((error = ddi_soft_state_init(&mc_statep,
35925cf1a30Sjl 	    sizeof (mc_opl_t), 1)) != 0)
36025cf1a30Sjl 		return (error);
36125cf1a30Sjl 
3620cc8ae86Sav 	if ((error = mc_poll_init()) != 0) {
3630cc8ae86Sav 		ddi_soft_state_fini(&mc_statep);
3640cc8ae86Sav 		return (error);
3650cc8ae86Sav 	}
3660cc8ae86Sav 
36725cf1a30Sjl 	mutex_init(&mcmutex, NULL, MUTEX_DRIVER, NULL);
36825cf1a30Sjl 	if (&opl_get_mem_unum)
36925cf1a30Sjl 		opl_get_mem_unum = mc_get_mem_unum;
3700cc8ae86Sav 	if (&opl_get_mem_sid)
3710cc8ae86Sav 		opl_get_mem_sid = mc_get_mem_sid;
3720cc8ae86Sav 	if (&opl_get_mem_offset)
3730cc8ae86Sav 		opl_get_mem_offset = mc_get_mem_offset;
3740cc8ae86Sav 	if (&opl_get_mem_addr)
3750cc8ae86Sav 		opl_get_mem_addr = mc_get_mem_addr;
3760cc8ae86Sav 
3770cc8ae86Sav 	node = prom_rootnode();
3780cc8ae86Sav 	plen = prom_getproplen(node, "model");
3790cc8ae86Sav 
3800cc8ae86Sav 	if (plen > 0 && plen < sizeof (model)) {
3810cc8ae86Sav 		(void) prom_getprop(node, "model", model);
3820cc8ae86Sav 		model[plen] = '\0';
3830cc8ae86Sav 		if (strcmp(model, "FF1") == 0)
3840cc8ae86Sav 			plat_model = MODEL_FF1;
3850cc8ae86Sav 		else if (strcmp(model, "FF2") == 0)
3860cc8ae86Sav 			plat_model = MODEL_FF2;
3870cc8ae86Sav 		else if (strncmp(model, "DC", 2) == 0)
3880cc8ae86Sav 			plat_model = MODEL_DC;
38978ed97a7Sjl 		else if (strcmp(model, "IKKAKU") == 0)
39078ed97a7Sjl 			plat_model = MODEL_IKKAKU;
3910cc8ae86Sav 	}
39225cf1a30Sjl 
39325cf1a30Sjl 	error =  mod_install(&modlinkage);
39425cf1a30Sjl 	if (error != 0) {
39525cf1a30Sjl 		if (&opl_get_mem_unum)
39625cf1a30Sjl 			opl_get_mem_unum = NULL;
3970cc8ae86Sav 		if (&opl_get_mem_sid)
3980cc8ae86Sav 			opl_get_mem_sid = NULL;
3990cc8ae86Sav 		if (&opl_get_mem_offset)
4000cc8ae86Sav 			opl_get_mem_offset = NULL;
4010cc8ae86Sav 		if (&opl_get_mem_addr)
4020cc8ae86Sav 			opl_get_mem_addr = NULL;
40325cf1a30Sjl 		mutex_destroy(&mcmutex);
4040cc8ae86Sav 		mc_poll_fini();
40525cf1a30Sjl 		ddi_soft_state_fini(&mc_statep);
40625cf1a30Sjl 	}
40725cf1a30Sjl 	return (error);
40825cf1a30Sjl }
40925cf1a30Sjl 
41025cf1a30Sjl int
_fini(void)41125cf1a30Sjl _fini(void)
41225cf1a30Sjl {
41325cf1a30Sjl 	int error;
41425cf1a30Sjl 
41525cf1a30Sjl 	if ((error = mod_remove(&modlinkage)) != 0)
41625cf1a30Sjl 		return (error);
41725cf1a30Sjl 
41825cf1a30Sjl 	if (&opl_get_mem_unum)
41925cf1a30Sjl 		opl_get_mem_unum = NULL;
4200cc8ae86Sav 	if (&opl_get_mem_sid)
4210cc8ae86Sav 		opl_get_mem_sid = NULL;
4220cc8ae86Sav 	if (&opl_get_mem_offset)
4230cc8ae86Sav 		opl_get_mem_offset = NULL;
4240cc8ae86Sav 	if (&opl_get_mem_addr)
4250cc8ae86Sav 		opl_get_mem_addr = NULL;
42625cf1a30Sjl 
4270cc8ae86Sav 	mutex_destroy(&mcmutex);
4280cc8ae86Sav 	mc_poll_fini();
42925cf1a30Sjl 	ddi_soft_state_fini(&mc_statep);
43025cf1a30Sjl 
43125cf1a30Sjl 	return (0);
43225cf1a30Sjl }
43325cf1a30Sjl 
43425cf1a30Sjl int
_info(struct modinfo * modinfop)43525cf1a30Sjl _info(struct modinfo *modinfop)
43625cf1a30Sjl {
43725cf1a30Sjl 	return (mod_info(&modlinkage, modinfop));
43825cf1a30Sjl }
43925cf1a30Sjl 
4400cc8ae86Sav static void
mc_polling_thread()4410cc8ae86Sav mc_polling_thread()
4420cc8ae86Sav {
4430cc8ae86Sav 	mutex_enter(&mc_polling_lock);
4440cc8ae86Sav 	mc_pollthr_running = 1;
4450cc8ae86Sav 	while (!(mc_poll_cmd & MC_POLL_EXIT)) {
4460cc8ae86Sav 		mc_polling();
44707d06da5SSurya Prakki 		(void) cv_reltimedwait(&mc_polling_cv, &mc_polling_lock,
448d3d50737SRafael Vanoni 		    mc_timeout_period, TR_CLOCK_TICK);
4490cc8ae86Sav 	}
4500cc8ae86Sav 	mc_pollthr_running = 0;
4510cc8ae86Sav 
4520cc8ae86Sav 	/*
4530cc8ae86Sav 	 * signal if any one is waiting for this thread to exit.
4540cc8ae86Sav 	 */
4550cc8ae86Sav 	cv_signal(&mc_poll_exit_cv);
4560cc8ae86Sav 	mutex_exit(&mc_polling_lock);
4570cc8ae86Sav 	thread_exit();
4580cc8ae86Sav 	/* NOTREACHED */
4590cc8ae86Sav }
4600cc8ae86Sav 
4610cc8ae86Sav static int
mc_poll_init()4620cc8ae86Sav mc_poll_init()
4630cc8ae86Sav {
4640cc8ae86Sav 	mutex_init(&mc_polling_lock, NULL, MUTEX_DRIVER, NULL);
4650cc8ae86Sav 	cv_init(&mc_polling_cv, NULL, CV_DRIVER, NULL);
4660cc8ae86Sav 	cv_init(&mc_poll_exit_cv, NULL, CV_DRIVER, NULL);
4670cc8ae86Sav 	return (0);
4680cc8ae86Sav }
4690cc8ae86Sav 
4700cc8ae86Sav static void
mc_poll_fini()4710cc8ae86Sav mc_poll_fini()
4720cc8ae86Sav {
4730cc8ae86Sav 	mutex_enter(&mc_polling_lock);
4740cc8ae86Sav 	if (mc_pollthr_running) {
4750cc8ae86Sav 		mc_poll_cmd = MC_POLL_EXIT;
4760cc8ae86Sav 		cv_signal(&mc_polling_cv);
4770cc8ae86Sav 		while (mc_pollthr_running) {
4780cc8ae86Sav 			cv_wait(&mc_poll_exit_cv, &mc_polling_lock);
4790cc8ae86Sav 		}
4800cc8ae86Sav 	}
4810cc8ae86Sav 	mutex_exit(&mc_polling_lock);
4820cc8ae86Sav 	mutex_destroy(&mc_polling_lock);
4830cc8ae86Sav 	cv_destroy(&mc_polling_cv);
4840cc8ae86Sav 	cv_destroy(&mc_poll_exit_cv);
4850cc8ae86Sav }
4860cc8ae86Sav 
48725cf1a30Sjl static int
mc_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)48825cf1a30Sjl mc_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
48925cf1a30Sjl {
49025cf1a30Sjl 	mc_opl_t *mcp;
49125cf1a30Sjl 	int instance;
4920cc8ae86Sav 	int rv;
49325cf1a30Sjl 
49425cf1a30Sjl 	/* get the instance of this devi */
49525cf1a30Sjl 	instance = ddi_get_instance(devi);
49625cf1a30Sjl 
49725cf1a30Sjl 	switch (cmd) {
49825cf1a30Sjl 	case DDI_ATTACH:
49925cf1a30Sjl 		break;
50025cf1a30Sjl 	case DDI_RESUME:
50125cf1a30Sjl 		mcp = ddi_get_soft_state(mc_statep, instance);
5020cc8ae86Sav 		rv = mc_resume(mcp, MC_DRIVER_SUSPENDED);
5030cc8ae86Sav 		return (rv);
50425cf1a30Sjl 	default:
50525cf1a30Sjl 		return (DDI_FAILURE);
50625cf1a30Sjl 	}
50725cf1a30Sjl 
50825cf1a30Sjl 	if (ddi_soft_state_zalloc(mc_statep, instance) != DDI_SUCCESS)
50925cf1a30Sjl 		return (DDI_FAILURE);
51025cf1a30Sjl 
5110b240fcdSwh 	if (ddi_create_minor_node(devi, "mc-opl", S_IFCHR, instance,
5120b240fcdSwh 	    "ddi_mem_ctrl", 0) != DDI_SUCCESS) {
5130b240fcdSwh 		MC_LOG("mc_attach: create_minor_node failed\n");
5140b240fcdSwh 		return (DDI_FAILURE);
5150b240fcdSwh 	}
5160b240fcdSwh 
51725cf1a30Sjl 	if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) {
51825cf1a30Sjl 		goto bad;
51925cf1a30Sjl 	}
52025cf1a30Sjl 
5210cc8ae86Sav 	if (mc_timeout_period == 0) {
5220cc8ae86Sav 		mc_patrol_interval_sec = (int)ddi_getprop(DDI_DEV_T_ANY, devi,
523d8a0cca9Swh 		    DDI_PROP_DONTPASS, "mc-timeout-interval-sec",
524d8a0cca9Swh 		    mc_patrol_interval_sec);
525d8a0cca9Swh 		mc_timeout_period = drv_usectohz(1000000 *
526d8a0cca9Swh 		    mc_patrol_interval_sec / OPL_MAX_BOARDS);
5270cc8ae86Sav 	}
5280cc8ae86Sav 
52925cf1a30Sjl 	/* set informations in mc state */
53025cf1a30Sjl 	mcp->mc_dip = devi;
53125cf1a30Sjl 
53225cf1a30Sjl 	if (mc_board_add(mcp))
53325cf1a30Sjl 		goto bad;
53425cf1a30Sjl 
53525cf1a30Sjl 	insert_mcp(mcp);
5360cc8ae86Sav 
5370cc8ae86Sav 	/*
5380cc8ae86Sav 	 * Start the polling thread if it is not running already.
5390cc8ae86Sav 	 */
5400cc8ae86Sav 	mutex_enter(&mc_polling_lock);
5410cc8ae86Sav 	if (!mc_pollthr_running) {
5420cc8ae86Sav 		(void) thread_create(NULL, 0, (void (*)())mc_polling_thread,
543d8a0cca9Swh 		    NULL, 0, &p0, TS_RUN, mc_poll_priority);
5440cc8ae86Sav 	}
5450cc8ae86Sav 	mutex_exit(&mc_polling_lock);
54625cf1a30Sjl 	ddi_report_dev(devi);
54725cf1a30Sjl 
54825cf1a30Sjl 	return (DDI_SUCCESS);
54925cf1a30Sjl 
55025cf1a30Sjl bad:
5510b240fcdSwh 	ddi_remove_minor_node(devi, NULL);
55225cf1a30Sjl 	ddi_soft_state_free(mc_statep, instance);
55325cf1a30Sjl 	return (DDI_FAILURE);
55425cf1a30Sjl }
55525cf1a30Sjl 
55625cf1a30Sjl /* ARGSUSED */
55725cf1a30Sjl static int
mc_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)55825cf1a30Sjl mc_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
55925cf1a30Sjl {
5600cc8ae86Sav 	int rv;
56125cf1a30Sjl 	int instance;
56225cf1a30Sjl 	mc_opl_t *mcp;
56325cf1a30Sjl 
56425cf1a30Sjl 	/* get the instance of this devi */
56525cf1a30Sjl 	instance = ddi_get_instance(devi);
56625cf1a30Sjl 	if ((mcp = ddi_get_soft_state(mc_statep, instance)) == NULL) {
56725cf1a30Sjl 		return (DDI_FAILURE);
56825cf1a30Sjl 	}
56925cf1a30Sjl 
57025cf1a30Sjl 	switch (cmd) {
57125cf1a30Sjl 	case DDI_SUSPEND:
5720cc8ae86Sav 		rv = mc_suspend(mcp, MC_DRIVER_SUSPENDED);
5730cc8ae86Sav 		return (rv);
57425cf1a30Sjl 	case DDI_DETACH:
57525cf1a30Sjl 		break;
57625cf1a30Sjl 	default:
57725cf1a30Sjl 		return (DDI_FAILURE);
57825cf1a30Sjl 	}
57925cf1a30Sjl 
5800cc8ae86Sav 	delete_mcp(mcp);
58125cf1a30Sjl 	if (mc_board_del(mcp) != DDI_SUCCESS) {
58225cf1a30Sjl 		return (DDI_FAILURE);
58325cf1a30Sjl 	}
58425cf1a30Sjl 
5850b240fcdSwh 	ddi_remove_minor_node(devi, NULL);
5860b240fcdSwh 
58725cf1a30Sjl 	/* free up the soft state */
58825cf1a30Sjl 	ddi_soft_state_free(mc_statep, instance);
58925cf1a30Sjl 
59025cf1a30Sjl 	return (DDI_SUCCESS);
59125cf1a30Sjl }
59225cf1a30Sjl 
59325cf1a30Sjl /* ARGSUSED */
59425cf1a30Sjl static int
mc_open(dev_t * devp,int flag,int otyp,cred_t * credp)59525cf1a30Sjl mc_open(dev_t *devp, int flag, int otyp, cred_t *credp)
59625cf1a30Sjl {
59725cf1a30Sjl 	return (0);
59825cf1a30Sjl }
59925cf1a30Sjl 
60025cf1a30Sjl /* ARGSUSED */
60125cf1a30Sjl static int
mc_close(dev_t devp,int flag,int otyp,cred_t * credp)60225cf1a30Sjl mc_close(dev_t devp, int flag, int otyp, cred_t *credp)
60325cf1a30Sjl {
60425cf1a30Sjl 	return (0);
60525cf1a30Sjl }
60625cf1a30Sjl 
60725cf1a30Sjl /* ARGSUSED */
60825cf1a30Sjl static int
mc_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)60925cf1a30Sjl mc_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
610*bbe1232eSToomas Soome     int *rvalp)
61125cf1a30Sjl {
6120b240fcdSwh 	mc_flt_page_t flt_page;
6130b240fcdSwh 
6140b240fcdSwh 	if (cmd == MCIOC_FAULT_PAGE) {
615*bbe1232eSToomas Soome 		if (arg == (intptr_t)NULL)
6160b240fcdSwh 			return (EINVAL);
6170b240fcdSwh 
6180b240fcdSwh 		if (ddi_copyin((const void *)arg, (void *)&flt_page,
6190b240fcdSwh 		    sizeof (mc_flt_page_t), 0) < 0)
6200b240fcdSwh 			return (EFAULT);
6210b240fcdSwh 
6220b240fcdSwh 		return (mc_scf_log_event(&flt_page));
6230b240fcdSwh 	}
6240cc8ae86Sav #ifdef DEBUG
6250cc8ae86Sav 	return (mc_ioctl_debug(dev, cmd, arg, mode, credp, rvalp));
6260cc8ae86Sav #else
6270b240fcdSwh 	return (ENOTTY);
6280cc8ae86Sav #endif
62925cf1a30Sjl }
63025cf1a30Sjl 
63125cf1a30Sjl /*
63225cf1a30Sjl  * PA validity check:
633738dd194Shyw  * This function return 1 if the PA is a valid PA
634738dd194Shyw  * in the running Solaris instance i.e. in physinstall
635738dd194Shyw  * Otherwise, return 0.
63625cf1a30Sjl  */
63725cf1a30Sjl 
63825cf1a30Sjl /* ARGSUSED */
63925cf1a30Sjl static int
pa_is_valid(mc_opl_t * mcp,uint64_t addr)64025cf1a30Sjl pa_is_valid(mc_opl_t *mcp, uint64_t addr)
64125cf1a30Sjl {
64225cf1a30Sjl 	if (mcp->mlist == NULL)
64325cf1a30Sjl 		mc_get_mlist(mcp);
64425cf1a30Sjl 
64525cf1a30Sjl 	if (mcp->mlist && address_in_memlist(mcp->mlist, addr, 0)) {
64625cf1a30Sjl 		return (1);
64725cf1a30Sjl 	}
64825cf1a30Sjl 	return (0);
64925cf1a30Sjl }
65025cf1a30Sjl 
65125cf1a30Sjl /*
65225cf1a30Sjl  * mac-pa translation routines.
65325cf1a30Sjl  *
65425cf1a30Sjl  *    Input: mc driver state, (LSB#, Bank#, DIMM address)
65525cf1a30Sjl  *    Output: physical address
65625cf1a30Sjl  *
65725cf1a30Sjl  *    Valid   - return value:  0
65825cf1a30Sjl  *    Invalid - return value: -1
65925cf1a30Sjl  */
66025cf1a30Sjl static int
mcaddr_to_pa(mc_opl_t * mcp,mc_addr_t * maddr,uint64_t * pa)66125cf1a30Sjl mcaddr_to_pa(mc_opl_t *mcp, mc_addr_t *maddr, uint64_t *pa)
66225cf1a30Sjl {
66325cf1a30Sjl 	int i;
66425cf1a30Sjl 	uint64_t pa_offset = 0;
66525cf1a30Sjl 	int cs = (maddr->ma_dimm_addr >> CS_SHIFT) & 1;
66625cf1a30Sjl 	int bank = maddr->ma_bank;
66725cf1a30Sjl 	mc_addr_t maddr1;
66825cf1a30Sjl 	int bank0, bank1;
66925cf1a30Sjl 
67025cf1a30Sjl 	MC_LOG("mcaddr /LSB%d/B%d/%x\n", maddr->ma_bd, bank,
671d8a0cca9Swh 	    maddr->ma_dimm_addr);
67225cf1a30Sjl 
67325cf1a30Sjl 	/* loc validity check */
67425cf1a30Sjl 	ASSERT(maddr->ma_bd >= 0 && OPL_BOARD_MAX > maddr->ma_bd);
67525cf1a30Sjl 	ASSERT(bank >= 0 && OPL_BANK_MAX > bank);
67625cf1a30Sjl 
67725cf1a30Sjl 	/* Do translation */
67825cf1a30Sjl 	for (i = 0; i < PA_BITS_FOR_MAC; i++) {
67925cf1a30Sjl 		int pa_bit = 0;
68025cf1a30Sjl 		int mc_bit = mcp->mc_trans_table[cs][i];
68125cf1a30Sjl 		if (mc_bit < MC_ADDRESS_BITS) {
68225cf1a30Sjl 			pa_bit = (maddr->ma_dimm_addr >> mc_bit) & 1;
68325cf1a30Sjl 		} else if (mc_bit == MP_NONE) {
68425cf1a30Sjl 			pa_bit = 0;
68525cf1a30Sjl 		} else if (mc_bit == MP_BANK_0) {
68625cf1a30Sjl 			pa_bit = bank & 1;
68725cf1a30Sjl 		} else if (mc_bit == MP_BANK_1) {
68825cf1a30Sjl 			pa_bit = (bank >> 1) & 1;
68925cf1a30Sjl 		} else if (mc_bit == MP_BANK_2) {
69025cf1a30Sjl 			pa_bit = (bank >> 2) & 1;
69125cf1a30Sjl 		}
69225cf1a30Sjl 		pa_offset |= ((uint64_t)pa_bit) << i;
69325cf1a30Sjl 	}
69425cf1a30Sjl 	*pa = mcp->mc_start_address + pa_offset;
69525cf1a30Sjl 	MC_LOG("pa = %lx\n", *pa);
69625cf1a30Sjl 
69725cf1a30Sjl 	if (pa_to_maddr(mcp, *pa, &maddr1) == -1) {
6980cc8ae86Sav 		cmn_err(CE_WARN, "mcaddr_to_pa: /LSB%d/B%d/%x failed to "
6990cc8ae86Sav 		    "convert PA %lx\n", maddr->ma_bd, bank,
7000cc8ae86Sav 		    maddr->ma_dimm_addr, *pa);
70125cf1a30Sjl 		return (-1);
70225cf1a30Sjl 	}
70325cf1a30Sjl 
7040cc8ae86Sav 	/*
7050cc8ae86Sav 	 * In mirror mode, PA is always translated to the even bank.
7060cc8ae86Sav 	 */
70725cf1a30Sjl 	if (IS_MIRROR(mcp, maddr->ma_bank)) {
70825cf1a30Sjl 		bank0 = maddr->ma_bank & ~(1);
70925cf1a30Sjl 		bank1 = maddr1.ma_bank & ~(1);
71025cf1a30Sjl 	} else {
71125cf1a30Sjl 		bank0 = maddr->ma_bank;
71225cf1a30Sjl 		bank1 = maddr1.ma_bank;
71325cf1a30Sjl 	}
71425cf1a30Sjl 	/*
71525cf1a30Sjl 	 * there is no need to check ma_bd because it is generated from
71625cf1a30Sjl 	 * mcp.  They are the same.
71725cf1a30Sjl 	 */
718d8a0cca9Swh 	if ((bank0 == bank1) && (maddr->ma_dimm_addr ==
719d8a0cca9Swh 	    maddr1.ma_dimm_addr)) {
72025cf1a30Sjl 		return (0);
72125cf1a30Sjl 	} else {
7220b240fcdSwh 		MC_LOG("Translation error source /LSB%d/B%d/%x, "
723d8a0cca9Swh 		    "PA %lx, target /LSB%d/B%d/%x\n", maddr->ma_bd, bank,
724d8a0cca9Swh 		    maddr->ma_dimm_addr, *pa, maddr1.ma_bd, maddr1.ma_bank,
725d8a0cca9Swh 		    maddr1.ma_dimm_addr);
72625cf1a30Sjl 		return (-1);
72725cf1a30Sjl 	}
72825cf1a30Sjl }
72925cf1a30Sjl 
73025cf1a30Sjl /*
73125cf1a30Sjl  * PA to CS (used by pa_to_maddr).
73225cf1a30Sjl  */
73325cf1a30Sjl static int
pa_to_cs(mc_opl_t * mcp,uint64_t pa_offset)73425cf1a30Sjl pa_to_cs(mc_opl_t *mcp, uint64_t pa_offset)
73525cf1a30Sjl {
73625cf1a30Sjl 	int i;
737738dd194Shyw 	int cs = 1;
73825cf1a30Sjl 
73925cf1a30Sjl 	for (i = 0; i < PA_BITS_FOR_MAC; i++) {
74025cf1a30Sjl 		/* MAC address bit<29> is arranged on the same PA bit */
74125cf1a30Sjl 		/* on both table. So we may use any table. */
74225cf1a30Sjl 		if (mcp->mc_trans_table[0][i] == CS_SHIFT) {
74325cf1a30Sjl 			cs = (pa_offset >> i) & 1;
74425cf1a30Sjl 			break;
74525cf1a30Sjl 		}
74625cf1a30Sjl 	}
74725cf1a30Sjl 	return (cs);
74825cf1a30Sjl }
74925cf1a30Sjl 
75025cf1a30Sjl /*
75125cf1a30Sjl  * PA to DIMM (used by pa_to_maddr).
75225cf1a30Sjl  */
75325cf1a30Sjl /* ARGSUSED */
75425cf1a30Sjl static uint32_t
pa_to_dimm(mc_opl_t * mcp,uint64_t pa_offset)75525cf1a30Sjl pa_to_dimm(mc_opl_t *mcp, uint64_t pa_offset)
75625cf1a30Sjl {
75725cf1a30Sjl 	int i;
75825cf1a30Sjl 	int cs = pa_to_cs(mcp, pa_offset);
75925cf1a30Sjl 	uint32_t dimm_addr = 0;
76025cf1a30Sjl 
76125cf1a30Sjl 	for (i = 0; i < PA_BITS_FOR_MAC; i++) {
76225cf1a30Sjl 		int pa_bit_value = (pa_offset >> i) & 1;
76325cf1a30Sjl 		int mc_bit = mcp->mc_trans_table[cs][i];
76425cf1a30Sjl 		if (mc_bit < MC_ADDRESS_BITS) {
76525cf1a30Sjl 			dimm_addr |= pa_bit_value << mc_bit;
76625cf1a30Sjl 		}
76725cf1a30Sjl 	}
768738dd194Shyw 	dimm_addr |= cs << CS_SHIFT;
76925cf1a30Sjl 	return (dimm_addr);
77025cf1a30Sjl }
77125cf1a30Sjl 
77225cf1a30Sjl /*
77325cf1a30Sjl  * PA to Bank (used by pa_to_maddr).
77425cf1a30Sjl  */
77525cf1a30Sjl static int
pa_to_bank(mc_opl_t * mcp,uint64_t pa_offset)77625cf1a30Sjl pa_to_bank(mc_opl_t *mcp, uint64_t pa_offset)
77725cf1a30Sjl {
77825cf1a30Sjl 	int i;
77925cf1a30Sjl 	int cs = pa_to_cs(mcp, pa_offset);
78025cf1a30Sjl 	int bankno = mcp->mc_trans_table[cs][INDEX_OF_BANK_SUPPLEMENT_BIT];
78125cf1a30Sjl 
78225cf1a30Sjl 
78325cf1a30Sjl 	for (i = 0; i < PA_BITS_FOR_MAC; i++) {
78425cf1a30Sjl 		int pa_bit_value = (pa_offset >> i) & 1;
78525cf1a30Sjl 		int mc_bit = mcp->mc_trans_table[cs][i];
78625cf1a30Sjl 		switch (mc_bit) {
78725cf1a30Sjl 		case MP_BANK_0:
78825cf1a30Sjl 			bankno |= pa_bit_value;
78925cf1a30Sjl 			break;
79025cf1a30Sjl 		case MP_BANK_1:
79125cf1a30Sjl 			bankno |= pa_bit_value << 1;
79225cf1a30Sjl 			break;
79325cf1a30Sjl 		case MP_BANK_2:
79425cf1a30Sjl 			bankno |= pa_bit_value << 2;
79525cf1a30Sjl 			break;
79625cf1a30Sjl 		}
79725cf1a30Sjl 	}
79825cf1a30Sjl 
79925cf1a30Sjl 	return (bankno);
80025cf1a30Sjl }
80125cf1a30Sjl 
80225cf1a30Sjl /*
80325cf1a30Sjl  * PA to MAC address translation
80425cf1a30Sjl  *
80525cf1a30Sjl  *   Input: MAC driver state, physicall adress
80625cf1a30Sjl  *   Output: LSB#, Bank id, mac address
80725cf1a30Sjl  *
80825cf1a30Sjl  *    Valid   - return value:  0
80925cf1a30Sjl  *    Invalid - return value: -1
81025cf1a30Sjl  */
81125cf1a30Sjl 
81225cf1a30Sjl int
pa_to_maddr(mc_opl_t * mcp,uint64_t pa,mc_addr_t * maddr)81325cf1a30Sjl pa_to_maddr(mc_opl_t *mcp, uint64_t pa, mc_addr_t *maddr)
81425cf1a30Sjl {
81525cf1a30Sjl 	uint64_t pa_offset;
81625cf1a30Sjl 
817738dd194Shyw 	if (!mc_rangecheck_pa(mcp, pa))
81825cf1a30Sjl 		return (-1);
81925cf1a30Sjl 
82025cf1a30Sjl 	/* Do translation */
82125cf1a30Sjl 	pa_offset = pa - mcp->mc_start_address;
82225cf1a30Sjl 
82325cf1a30Sjl 	maddr->ma_bd = mcp->mc_board_num;
824aeb241b2Sav 	maddr->ma_phys_bd = mcp->mc_phys_board_num;
82525cf1a30Sjl 	maddr->ma_bank = pa_to_bank(mcp, pa_offset);
82625cf1a30Sjl 	maddr->ma_dimm_addr = pa_to_dimm(mcp, pa_offset);
827d8a0cca9Swh 	MC_LOG("pa %lx -> mcaddr /LSB%d/B%d/%x\n", pa_offset, maddr->ma_bd,
828d8a0cca9Swh 	    maddr->ma_bank, maddr->ma_dimm_addr);
82925cf1a30Sjl 	return (0);
83025cf1a30Sjl }
83125cf1a30Sjl 
8320cc8ae86Sav /*
8330cc8ae86Sav  * UNUM format for DC is "/CMUnn/MEMxyZ", where
8340cc8ae86Sav  *	nn = 00..03 for DC1 and 00..07 for DC2 and 00..15 for DC3.
8350cc8ae86Sav  *	x = MAC 0..3
8360cc8ae86Sav  *	y = 0..3 (slot info).
8370cc8ae86Sav  *	Z = 'A' or 'B'
8380cc8ae86Sav  *
8390cc8ae86Sav  * UNUM format for FF1 is "/MBU_A/MEMBx/MEMyZ", where
8400cc8ae86Sav  *	x = 0..3 (MEMB number)
841