Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: SS_CKMemory.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | #include "SS_CKMemory.h" | |
22 | ||
23 | SS_CKMemory::SS_CKMemory(SS_Memory *mem)/*{{{*/ | |
24 | :ss_mem(mem), | |
25 | debug_CK(getenv("CK_CHIPKILL_DEBUG") != NULL) | |
26 | { | |
27 | } | |
28 | /*}}}*/ | |
29 | SS_CKMemory::~SS_CKMemory()/*{{{*/ | |
30 | { | |
31 | } | |
32 | /*}}}*/ | |
33 | ||
34 | uint64_t SS_CKMemory::ras_ld_buf( uint64_t addr, uint_t size )/*{{{*/ | |
35 | { | |
36 | mem_xact.paddr(addr); | |
37 | mem_xact.size(size); | |
38 | mem_xact.access(MemoryTransaction::READ); | |
39 | mem_xact.referenceType(MemoryTransaction::DATA); | |
40 | ||
41 | read_dram_error_corrected(mem_xact); | |
42 | return mem_xact.getData(); | |
43 | } | |
44 | /*}}}*/ | |
45 | void SS_CKMemory::ras_ld( uint64_t addr, uint_t size, uint64_t* data )/*{{{*/ | |
46 | { | |
47 | mem_xact.paddr(addr); | |
48 | mem_xact.size(size); | |
49 | mem_xact.access(MemoryTransaction::READ); | |
50 | mem_xact.referenceType(MemoryTransaction::DATA); | |
51 | ||
52 | read_dram_error_corrected(mem_xact); | |
53 | for (uint_t i=0; size; i++, size -= 8) | |
54 | data[i]= mem_xact.getData(i); | |
55 | } | |
56 | /*}}}*/ | |
57 | ||
58 | ||
59 | ||
60 | uint32_t SS_CKMemory::fetch32( uint64_t addr )/*{{{*/ | |
61 | { | |
62 | mem_xact.paddr(addr); | |
63 | mem_xact.size(4); | |
64 | mem_xact.access(MemoryTransaction::READ); | |
65 | mem_xact.referenceType(MemoryTransaction::INSTR); | |
66 | ||
67 | read_dram_error_corrected(mem_xact); | |
68 | return mem_xact.getData(); | |
69 | } | |
70 | /*}}}*/ | |
71 | void SS_CKMemory::fetch256( uint64_t addr, uint64_t data[4] )/*{{{*/ | |
72 | { | |
73 | mem_xact.paddr(addr); | |
74 | mem_xact.size(32); | |
75 | mem_xact.access(MemoryTransaction::READ); | |
76 | mem_xact.referenceType(MemoryTransaction::INSTR); | |
77 | ||
78 | read_dram_error_corrected(mem_xact); | |
79 | uint_t size = 32; | |
80 | for (uint_t i=0; size; i++, size -= 8) | |
81 | data[i]= mem_xact.getData(i); | |
82 | } | |
83 | /*}}}*/ | |
84 | void SS_CKMemory::fetch512( uint64_t addr, uint64_t data[8] )/*{{{*/ | |
85 | { | |
86 | mem_xact.paddr(addr); | |
87 | mem_xact.size(64); | |
88 | mem_xact.access(MemoryTransaction::READ); | |
89 | mem_xact.referenceType(MemoryTransaction::INSTR); | |
90 | ||
91 | read_dram_error_corrected(mem_xact); | |
92 | ||
93 | uint_t size = 64; | |
94 | for (uint_t i=0; size; i++, size -= 8) | |
95 | data[i]= mem_xact.getData(i); | |
96 | } | |
97 | /*}}}*/ | |
98 | ||
99 | void SS_CKMemory::st8( uint64_t addr, uint8_t data )/*{{{*/ | |
100 | { | |
101 | ss_mem->st8(addr,data); | |
102 | } | |
103 | /*}}}*/ | |
104 | void SS_CKMemory::st16( uint64_t addr, uint16_t data )/*{{{*/ | |
105 | { | |
106 | ss_mem->st16(addr,data); | |
107 | } | |
108 | /*}}}*/ | |
109 | void SS_CKMemory::st32( uint64_t addr, uint32_t data )/*{{{*/ | |
110 | { | |
111 | ss_mem->st32(addr,data); | |
112 | } | |
113 | /*}}}*/ | |
114 | void SS_CKMemory::st64( uint64_t addr, uint64_t data )/*{{{*/ | |
115 | { | |
116 | ss_mem->st64(addr,data); | |
117 | } | |
118 | /*}}}*/ | |
119 | void SS_CKMemory::st128( uint64_t addr, uint64_t data[2] )/*{{{*/ | |
120 | { | |
121 | ss_mem->st128(addr,data); | |
122 | } | |
123 | /*}}}*/ | |
124 | void SS_CKMemory::st512( uint64_t addr, uint64_t data[8] )/*{{{*/ | |
125 | { | |
126 | ss_mem->st512(addr,data); | |
127 | } | |
128 | /*}}}*/ | |
129 | ||
130 | uint8_t SS_CKMemory::ld8u ( uint64_t addr )/*{{{*/ | |
131 | { | |
132 | return ras_ld_buf(addr,1); | |
133 | } | |
134 | /*}}}*/ | |
135 | int8_t SS_CKMemory::ld8s( uint64_t addr )/*{{{*/ | |
136 | { | |
137 | return ras_ld_buf(addr,1); | |
138 | } | |
139 | /*}}}*/ | |
140 | uint16_t SS_CKMemory::ld16u( uint64_t addr )/*{{{*/ | |
141 | { | |
142 | return ras_ld_buf(addr,2); | |
143 | } | |
144 | /*}}}*/ | |
145 | int16_t SS_CKMemory::ld16s( uint64_t addr )/*{{{*/ | |
146 | { | |
147 | return ras_ld_buf(addr,2); | |
148 | } | |
149 | /*}}}*/ | |
150 | uint32_t SS_CKMemory::ld32u( uint64_t addr )/*{{{*/ | |
151 | { | |
152 | return ras_ld_buf(addr,4); | |
153 | } | |
154 | /*}}}*/ | |
155 | int32_t SS_CKMemory::ld32s( uint64_t addr )/*{{{*/ | |
156 | { | |
157 | return ras_ld_buf(addr,4); | |
158 | } | |
159 | /*}}}*/ | |
160 | uint64_t SS_CKMemory::ld64( uint64_t addr )/*{{{*/ | |
161 | { | |
162 | return ras_ld_buf(addr,8); | |
163 | } | |
164 | /*}}}*/ | |
165 | void SS_CKMemory::ld128( uint64_t addr, uint64_t data[2] ) /*{{{*/ | |
166 | { | |
167 | ras_ld(addr,16,data); | |
168 | } | |
169 | /*}}}*/ | |
170 | void SS_CKMemory::ld256( uint64_t addr, uint64_t data[4] )/*{{{*/ | |
171 | { | |
172 | ras_ld(addr,32,data); | |
173 | } | |
174 | /*}}}*/ | |
175 | void SS_CKMemory::ld512( uint64_t addr, uint64_t data[8] )/*{{{*/ | |
176 | { | |
177 | ras_ld(addr,64,data); | |
178 | } | |
179 | /*}}}*/ | |
180 | ||
181 | void SS_CKMemory::st64partial( uint64_t addr, uint64_t data, uint64_t mask ) /*{{{*/ | |
182 | { | |
183 | ss_mem->st64partial(addr,data,mask); | |
184 | } | |
185 | /*}}}*/ | |
186 | ||
187 | void SS_CKMemory::ld128atomic( uint64_t addr, uint64_t data[2] )/*{{{*/ | |
188 | { | |
189 | ras_ld(addr,16,data); | |
190 | } | |
191 | /*}}}*/ | |
192 | ||
193 | uint8_t SS_CKMemory::ldstub( uint64_t addr )/*{{{*/ | |
194 | { | |
195 | mem_xact.referenceType(MemoryTransaction::DATA); | |
196 | mem_xact.paddr(addr); | |
197 | mem_xact.size(1); | |
198 | mem_xact.access(MemoryTransaction::READ|MemoryTransaction::ATOMIC); | |
199 | ||
200 | read_dram_error_corrected(mem_xact); | |
201 | uint64_t data = mem_xact.getData(); | |
202 | ss_mem->poke8(addr,0xff); | |
203 | return data; | |
204 | } | |
205 | /*}}}*/ | |
206 | uint32_t SS_CKMemory::swap( uint64_t addr, uint32_t rd )/*{{{*/ | |
207 | { | |
208 | mem_xact.referenceType(MemoryTransaction::DATA); | |
209 | mem_xact.paddr(addr); | |
210 | mem_xact.size(4); | |
211 | mem_xact.access(MemoryTransaction::READ|MemoryTransaction::ATOMIC); | |
212 | ||
213 | read_dram_error_corrected(mem_xact); | |
214 | uint64_t data = mem_xact.getData(); | |
215 | ss_mem->poke32(addr,rd); | |
216 | return data; | |
217 | } | |
218 | /*}}}*/ | |
219 | uint64_t SS_CKMemory::casx( uint64_t addr, uint64_t rd, uint64_t rs2 )/*{{{*/ | |
220 | { | |
221 | mem_xact.referenceType(MemoryTransaction::DATA); | |
222 | mem_xact.paddr(addr); | |
223 | mem_xact.size(8); | |
224 | mem_xact.access(MemoryTransaction::READ|MemoryTransaction::ATOMIC); | |
225 | ||
226 | read_dram_error_corrected(mem_xact); | |
227 | ||
228 | uint64_t data = mem_xact.getData(); | |
229 | if (data == rs2) | |
230 | { | |
231 | ss_mem->poke64(addr,rd); | |
232 | } | |
233 | return data; | |
234 | } | |
235 | /*}}}*/ | |
236 | uint32_t SS_CKMemory::cas( uint64_t addr, uint32_t rd, uint32_t rs2 )/*{{{*/ | |
237 | { | |
238 | mem_xact.referenceType(MemoryTransaction::DATA); | |
239 | mem_xact.paddr(addr); | |
240 | mem_xact.size(4); | |
241 | mem_xact.access(MemoryTransaction::READ|MemoryTransaction::ATOMIC); | |
242 | ||
243 | read_dram_error_corrected(mem_xact); | |
244 | ||
245 | uint32_t data = mem_xact.getData(); | |
246 | if (data == rs2) | |
247 | { | |
248 | ss_mem->poke32(addr,rd); | |
249 | } | |
250 | return data; | |
251 | } | |
252 | /*}}}*/ | |
253 | ||
254 | // read_dram_error_corrected() reads the memory specified in a | |
255 | // MemoryTransaction, memXact, and applies Chip-Kill error correction | |
256 | // to the data as needed. | |
257 | // | |
258 | // Returns false if memXact specifies no Chip-Kill correction or if the | |
259 | // access is to the I/O space (where CK doesn't apply). | |
260 | ||
261 | bool SS_CKMemory::read_dram_error_corrected(MemoryTransaction &memXact)/*{{{*/ | |
262 | { | |
263 | if (memXact.writeXact()) { | |
264 | fprintf(stderr, "SS_CKMemory::corrrectDramError() " | |
265 | "WRITE or READ_WRITE memXact."); | |
266 | exit(-1); | |
267 | } | |
268 | ||
269 | if( memXact.size() < 8 ){ | |
270 | memXact.setData(read_short_corrected_dram_data(memXact.paddr(), | |
271 | memXact.size())); | |
272 | } else { | |
273 | if( memXact.size() % 8 ){ | |
274 | fprintf(stderr, "Read of size %d, is not a multiple of 8 bytes", | |
275 | memXact.size() ); | |
276 | exit(-1); | |
277 | } | |
278 | uint_t size = memXact.size() / 8; | |
279 | for( uint_t i = 0; i < size; ++i ){ | |
280 | uint64_t data = read_corrected_dram_data(memXact.paddr() + i * 8, 8); | |
281 | memXact.setData(i, data); | |
282 | } | |
283 | } | |
284 | ||
285 | return true; | |
286 | } | |
287 | ||
288 | // read_corrected_dram_data() reads Chip-Kill corrected data from | |
289 | // paddress. Allowed sizes are 1, 2, 4, and multiples of 8. | |
290 | ||
291 | uint64_t SS_CKMemory::read_corrected_dram_data(uint64_t paddress, | |
292 | uint8_t size)/*{{{*/ | |
293 | { | |
294 | if (size < 8) { | |
295 | return read_short_corrected_dram_data(paddress, size); | |
296 | } | |
297 | ||
298 | if (size % 8) { | |
299 | fprintf(stderr, "SS_CKMemory::readCorrectedDramData: read of " | |
300 | "size %d, is not a multiple of 8 bytes", size); | |
301 | } | |
302 | ||
303 | uint64_t ckPaddr = paddress & ~(DRAM_LINE_LENGTH - 1); | |
304 | BL_CKEccFile::ChipKillLine line = read_raw_CK_line(ckPaddr); | |
305 | if (ecc_exists(ckPaddr)) { | |
306 | uint64_t storedECC = fetch_ecc(ckPaddr); | |
307 | ||
308 | uint64_t old_msdw = line.msdw; | |
309 | uint64_t old_lsdw = line.lsdw; | |
310 | ||
311 | // if debugging Chip-Kill, inject data errors | |
312 | if (debug_CK) { | |
313 | if (random() % 2) | |
314 | line.msdw ^= ((random() % 16) << (4*(random() % 16))); | |
315 | else | |
316 | line.lsdw ^= ((random() % 16) << (4*(random() % 16))); | |
317 | } | |
318 | BL_CKSyndrome ckSyndrome(line, storedECC); | |
319 | ||
320 | // if there is no error for this CK line, remove its ECC value | |
321 | if (ckSyndrome.noError()) { | |
322 | dram_ecc_map.erase(ckPaddr); | |
323 | } else { // try to fix the line | |
324 | ckSyndrome.correctChipKillLine(line); | |
325 | } | |
326 | // if the error weren't fixed, die | |
327 | if (debug_CK && old_msdw != line.msdw && old_lsdw != line.lsdw) { | |
328 | fprintf(stderr,"SS_CKMemory::" | |
329 | "readCorrectedDramData(): " | |
330 | "Chip-Kill failed"); | |
331 | ||
332 | exit(-1); | |
333 | } | |
334 | } | |
335 | ||
336 | return (paddress & (DRAM_LINE_LENGTH/2)) ? line.lsdw : line.msdw; | |
337 | } | |
338 | /*}}}*/ | |
339 | ||
340 | // read_short_corrected_dram_data() reads Chip-Kill corrected data from | |
341 | // paddress. Allowed sizes are 1, 2, 4. | |
342 | ||
343 | uint64_t SS_CKMemory::read_short_corrected_dram_data(uint64_t paddress, | |
344 | uint8_t size)/*{{{*/ | |
345 | { | |
346 | uint64_t data = read_corrected_dram_data(paddress & ~0x07ULL , 8); | |
347 | switch( size ) | |
348 | { | |
349 | case 4: | |
350 | data = ( data >> ( 32 - (paddress & 0x04ULL) * 8)) & 0x0ffffffff; | |
351 | break; | |
352 | case 2: | |
353 | data = ( data >> ( 48 - (paddress & 0x06ULL) * 8)) & 0x0ffff; | |
354 | break; | |
355 | case 1: | |
356 | data = ( data >> ( 56 - (paddress & 0x07ULL) * 8)) & 0x0ff; | |
357 | break; | |
358 | default: | |
359 | fprintf(stderr, "Read of size %d is not supported. Reads must be " | |
360 | "1, 2, 4, or 8 bytes.", size ); | |
361 | exit; | |
362 | } | |
363 | ||
364 | /*fprintf(stderr, "Read of %d bytes of data from 0x%0.16llx data=%0.16llx\n", | |
365 | size, paddress, data );*/ | |
366 | ||
367 | return data; | |
368 | } | |
369 | /*}}}*/ |