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
mc_get_mem_alignment()82 mc_get_mem_alignment()
83 {
84 return (STARFIRE_MC_MEMBOARD_ALIGNMENT);
85 }
86
87 uint64_t
mc_get_asr_addr(pnode_t nodeid)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)®) < 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
mc_get_idle_addr(pnode_t nodeid)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)®) < 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
mc_get_dimm_size(pnode_t nodeid)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)®) < 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
mc_get_alignment_mask(pnode_t nodeid)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)®) < 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
mc_read_asr(pnode_t nodeid,uint_t * mcregp)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
mc_write_asr(pnode_t nodeid,uint_t mcreg)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
mc_asr_to_pa(uint_t mcreg)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
mc_pa_to_asr(uint_t masr,uint64_t pa)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