xref: /titanic_50/usr/src/uts/sun4u/starfire/io/memctrl.c (revision 49f9b365248ee858ee91baa36eab27c5200f6dca)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Starfire Memory Controller specific routines.
31  */
32 
33 #include <sys/debug.h>
34 #include <sys/types.h>
35 #include <sys/errno.h>
36 #include <sys/dditypes.h>
37 #include <sys/conf.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 #include <sys/sunndi.h>
41 #include <sys/ddi_impldefs.h>
42 #include <sys/promif.h>
43 #include <sys/machsystm.h>
44 
45 #include <sys/starfire.h>
46 
47 struct mc_dimm_table {
48 	int	mc_type;
49 	int	mc_module_size;		/* module size in MB */
50 };
51 
52 static struct mc_dimm_table dimmsize_table[] = {
53 	{ 4,	8 },
54 	{ 6,	8 },
55 	{ 11,	32 },
56 	{ 15,	128 },
57 	{ 0,	0 }
58 };
59 
60 #define	MC_MB(mb) ((mb) * 1048576ull)
61 
62 struct mc_seg_size {
63 	uint_t		seg_mask;
64 	uint64_t	seg_size;
65 };
66 
67 struct mc_seg_size mc_seg_table[] = {
68 	{ 0x7f,	MC_MB(64)	},
69 	{ 0x7e,	MC_MB(128)	},
70 	{ 0x7c,	MC_MB(256)	},
71 	{ 0x78,	MC_MB(512)	},
72 	{ 0x70,	MC_MB(1024)	},
73 	{ 0x60,	MC_MB(2048)	},
74 	{ 0x40,	MC_MB(4096)	},
75 	{ 0,	0		}
76 };
77 
78 /*
79  * Alignment of memory between MC's.
80  */
81 uint64_t
82 mc_get_mem_alignment()
83 {
84 	return (STARFIRE_MC_MEMBOARD_ALIGNMENT);
85 }
86 
87 uint64_t
88 mc_get_asr_addr(pnode_t nodeid)
89 {
90 	int		rlen;
91 	uint64_t	psi_addr;
92 	struct sf_memunit_regspec	reg;
93 
94 	rlen = prom_getproplen(nodeid, "reg");
95 	if (rlen != sizeof (struct sf_memunit_regspec))
96 		return ((uint64_t)-1);
97 
98 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
99 		return ((uint64_t)-1);
100 
101 	psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32;
102 	psi_addr |= (uint64_t)reg.regspec_addr_lo;
103 
104 	return (STARFIRE_MC_ASR_ADDR(psi_addr));
105 }
106 
107 uint64_t
108 mc_get_idle_addr(pnode_t nodeid)
109 {
110 	int		rlen;
111 	uint64_t	psi_addr;
112 	struct sf_memunit_regspec	reg;
113 
114 	rlen = prom_getproplen(nodeid, "reg");
115 	if (rlen != sizeof (struct sf_memunit_regspec))
116 		return ((uint64_t)-1);
117 
118 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
119 		return ((uint64_t)-1);
120 
121 	psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32;
122 	psi_addr |= (uint64_t)reg.regspec_addr_lo;
123 
124 	return (STARFIRE_MC_IDLE_ADDR(psi_addr));
125 }
126 
127 int
128 mc_get_dimm_size(pnode_t nodeid)
129 {
130 	uint64_t	psi_addr;
131 	uint_t		dimmtype;
132 	int		i, rlen;
133 	struct sf_memunit_regspec	reg;
134 
135 	rlen = prom_getproplen(nodeid, "reg");
136 	if (rlen != sizeof (struct sf_memunit_regspec))
137 		return (-1);
138 
139 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
140 		return (-1);
141 
142 	psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32;
143 	psi_addr |= (uint64_t)reg.regspec_addr_lo;
144 	psi_addr = STARFIRE_MC_DIMMTYPE_ADDR(psi_addr);
145 
146 	if (psi_addr == (uint64_t)-1)
147 		return (-1);
148 
149 	dimmtype = ldphysio(psi_addr);
150 	dimmtype &= STARFIRE_MC_DIMMSIZE_MASK;
151 
152 	for (i = 0; dimmsize_table[i].mc_type != 0; i++)
153 		if (dimmsize_table[i].mc_type == dimmtype)
154 			break;
155 
156 	return (dimmsize_table[i].mc_module_size);
157 }
158 
159 uint64_t
160 mc_get_alignment_mask(pnode_t nodeid)
161 {
162 	uint64_t	psi_addr, seg_sz;
163 	uint_t		mcreg, seg_sz_mask;
164 	int		i, rlen;
165 	struct sf_memunit_regspec	reg;
166 
167 	rlen = prom_getproplen(nodeid, "reg");
168 	if (rlen != sizeof (struct sf_memunit_regspec))
169 		return (-1);
170 
171 	if (prom_getprop(nodeid, "reg", (caddr_t)&reg) < 0)
172 		return (-1);
173 
174 	psi_addr = ((uint64_t)reg.regspec_addr_hi) << 32;
175 	psi_addr |= (uint64_t)reg.regspec_addr_lo;
176 	psi_addr = STARFIRE_MC_ASR_ADDR(psi_addr);
177 
178 	if (psi_addr == (uint64_t)-1)
179 		return (-1);
180 
181 	mcreg = ldphysio(psi_addr);
182 	seg_sz_mask = (mcreg & STARFIRE_MC_MASK_MASK) >> 8;
183 
184 	for (i = 0; mc_seg_table[i].seg_size != 0; i++)
185 		if (mc_seg_table[i].seg_mask == seg_sz_mask)
186 			break;
187 
188 	if (mc_seg_table[i].seg_size == 0)
189 		seg_sz = mc_get_mem_alignment();
190 	else
191 		seg_sz = mc_seg_table[i].seg_size;
192 
193 #ifdef DEBUG
194 	printf("nodeid %x, mc asr addr %lx, val %x, seg_sz_mask %x, "
195 	    "seg_sz %lx\n", nodeid, psi_addr, mcreg, seg_sz_mask, seg_sz);
196 #endif /* DEBUG */
197 
198 	return (seg_sz - 1);
199 }
200 
201 int
202 mc_read_asr(pnode_t nodeid, uint_t *mcregp)
203 {
204 	uint64_t	psi_addr;
205 
206 	*mcregp = 0;
207 
208 	psi_addr = mc_get_asr_addr(nodeid);
209 	if (psi_addr == (uint64_t)-1)
210 		return (-1);
211 
212 	*mcregp = ldphysio(psi_addr);
213 
214 	return (0);
215 }
216 
217 int
218 mc_write_asr(pnode_t nodeid, uint_t mcreg)
219 {
220 	uint_t		mcreg_rd;
221 	uint64_t	psi_addr;
222 
223 	psi_addr = mc_get_asr_addr(nodeid);
224 	if (psi_addr == (uint64_t)-1)
225 		return (-1);
226 
227 	stphysio(psi_addr, mcreg);
228 
229 	mcreg_rd = ldphysio(psi_addr);
230 	ASSERT(mcreg_rd == mcreg);
231 
232 	return ((mcreg_rd != mcreg) ? -1 : 0);
233 }
234 
235 uint64_t
236 mc_asr_to_pa(uint_t mcreg)
237 {
238 	uint64_t	pa, masr, addrmask, lowbitmask;
239 
240 	/*
241 	 * Remove memory present bit.
242 	 */
243 	masr = (uint64_t)(mcreg & ~STARFIRE_MC_MEM_PRESENT_MASK);
244 	/*
245 	 * Get mask for bits 32-26.
246 	 */
247 	lowbitmask = masr & (uint64_t)STARFIRE_MC_MASK_MASK;
248 	lowbitmask <<= STARFIRE_MC_MASK_SHIFT;
249 	addrmask = STARFIRE_MC_ADDR_HIBITS | lowbitmask;
250 
251 	pa = (masr << STARFIRE_MC_BASE_SHIFT) & addrmask;
252 
253 	return (pa);
254 }
255 
256 uint_t
257 mc_pa_to_asr(uint_t masr, uint64_t pa)
258 {
259 	uint64_t	addrmask, lowbitmask;
260 	uint_t		base;
261 
262 	/*
263 	 * Get mask for bits 32-26.
264 	 */
265 	lowbitmask = masr & (uint64_t)STARFIRE_MC_MASK_MASK;
266 	lowbitmask <<= STARFIRE_MC_MASK_SHIFT;
267 	addrmask = STARFIRE_MC_ADDR_HIBITS | lowbitmask;
268 
269 	base  = (pa & addrmask) >> STARFIRE_MC_BASE_SHIFT;
270 	masr &= ~ STARFIRE_MC_MEM_BASEADDR_MASK;
271 	masr |= base & STARFIRE_MC_MEM_BASEADDR_MASK;
272 
273 	ASSERT(mc_asr_to_pa(masr) == pa);
274 
275 	return (masr);
276 }
277