Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: ncu.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 "ncu.h" | |
22 | ||
23 | static const char *n2ncu_help = "SAM N2 NCU module\n\ | |
24 | Sysconf format is :\n\ | |
25 | sysconf n2_ncu <instance_name> \n\ | |
26 | For UI help type <instance name> \n\ | |
27 | For module specific info type \"modinfo <instance name>\""; | |
28 | ||
29 | static int access_ncu(uint32_t cpuid, void* obj, uint64_t paddr, mmi_bool_t wr, uint32_t size, uint64_t* buf, uint8_t bytemask){ | |
30 | n2Ncu * ncu = (n2Ncu*)obj; | |
31 | return ncu->access_regs(cpuid,paddr,wr,size,buf,bytemask); | |
32 | } | |
33 | ||
34 | int n2ncu_ui_cmd(void * obj, int argc, char * argv[]){ | |
35 | n2Ncu * i = (n2Ncu *)obj; | |
36 | i->handle_ui(argc, argv); | |
37 | return 0; | |
38 | } | |
39 | ||
40 | ||
41 | const uint64_t n2Ncu::dumpRegsV1[25] = { | |
42 | INT_MAN, | |
43 | MONDO_INT_VEC, | |
44 | SER_NUM, | |
45 | EFU_STAT, | |
46 | BANK_ENABLE, | |
47 | BANK_ENABLE_STATUS, | |
48 | L2_IDX_HASH_EN, | |
49 | L2_IDX_HASH_EN_STATUS, | |
50 | PCIE_A_MEM32_OFFSET_BASE, | |
51 | PCIE_A_MEM32_OFFSET_MASK, | |
52 | PCIE_A_MEM64_OFFSET_BASE, | |
53 | PCIE_A_MEM64_OFFSET_MASK, | |
54 | PCIE_A_IOCON_OFFSET_BASE, | |
55 | PCIE_A_IOCON_OFFSET_MASK, | |
56 | PCIE_A_FSH, | |
57 | SOC_ESR, | |
58 | SOC_LOG_ENABLE, | |
59 | SOC_INTERRUPT_ENABLE, | |
60 | SOC_ERROR_INJECTION, | |
61 | SOC_FATAL_ERROR_ENABLE, | |
62 | SOC_SII_ERROR_SYNDROME, | |
63 | SOC_NCU_ERROR_SYNDROME, | |
64 | MONDO_INT_DATA0, | |
65 | MONDO_INT_DATA1, | |
66 | MONDO_INT_BUSY, | |
67 | }; | |
68 | ||
69 | const char * Module::get_help_string(){ | |
70 | return n2ncu_help; | |
71 | } | |
72 | ||
73 | Module * Module::create(const char *_modname, const char *_instance_name){ | |
74 | return new n2Ncu(_modname, _instance_name); | |
75 | } | |
76 | ||
77 | n2Ncu::n2Ncu(const char *_modname, const char *_instance_name) | |
78 | : Module(_modname, _instance_name){ | |
79 | ||
80 | ncu_init(); | |
81 | mmi_register_instance_cmd(getInstance(),n2ncu_help,n2ncu_ui_cmd); | |
82 | current_dump_version = strdup("v1.0"); | |
83 | } | |
84 | ||
85 | ||
86 | void n2Ncu::ncu_init(){ | |
87 | uint64_t device; | |
88 | int i; | |
89 | ||
90 | //pthread_mutex_init(&ncu_lock, NULL); | |
91 | ||
92 | /* | |
93 | * setup init value (NCU spec, v0.99) | |
94 | */ | |
95 | for (device=0; device < NCU_DEV_MAX; device++) { | |
96 | regs.int_man[device] = 0x0; | |
97 | } | |
98 | ||
99 | regs.mondo_int_vec = 0x0; | |
100 | regs.ser_num = 0xdeadbeef; | |
101 | regs.efu_stat = MASK64(63,0); | |
102 | regs.bank_enb = 0xff; | |
103 | regs.bank_enb_stat = 0x3cf; | |
104 | regs.l2_idx_hash_en_stat = false; | |
105 | regs.pcie_a_mem32_offset_base = 0x0; | |
106 | regs.pcie_a_mem32_offset_mask = MASK64(39,36); | |
107 | regs.pcie_a_mem64_offset_base = 0x0; | |
108 | regs.pcie_a_mem64_offset_mask = MASK64(39,36); | |
109 | regs.pcie_a_iocon_offset_base = 0x0; | |
110 | regs.pcie_a_iocon_offset_mask = MASK64(39,36); | |
111 | regs.pcie_a_fsh = 0x0; | |
112 | regs.soc_esr = 0x0; | |
113 | regs.soc_log_enb = 0x1fffffff; | |
114 | regs.soc_intr_enb = 0x0; | |
115 | regs.soc_err_inject = 0x0; | |
116 | regs.soc_fatal_enb = 0x0; | |
117 | regs.soc_sii_err_syndrome = 0x0; | |
118 | regs.soc_ncu_err_syndrome = 0x0; | |
119 | ||
120 | for (i = 0; i < NCU_TARGETS; i++) { | |
121 | regs.mondo_int_data0[i] = 0x0; | |
122 | regs.mondo_int_data1[i] = 0x0; | |
123 | regs.mondo_int_busy[i] = 0x0; //MASK64(6,6); | |
124 | } | |
125 | return; | |
126 | } | |
127 | ||
128 | ||
129 | ||
130 | // support 8 byte reads/writes of registers. | |
131 | int n2Ncu::access_regs(uint32_t cpuid, uint64_t paddr, mmi_bool_t wr, uint32_t size,\ | |
132 | uint64_t* buf, uint8_t bytemask){ | |
133 | ||
134 | if(size != 8){ | |
135 | debug_err("%s ERROR: %s access of size %d at addr %llx\n", \ | |
136 | getName(),wr?"WITE":"READ",size,paddr); | |
137 | return -1; | |
138 | } | |
139 | ||
140 | if(paddr & 7){ | |
141 | debug_err("%s ERROR: unaligned %s access of size %d at addr %llx\n", \ | |
142 | getName(),wr?"WITE":"READ",size,paddr); | |
143 | return -1; | |
144 | } | |
145 | ||
146 | uint64_t reg = paddr & NCU_REG_MASK; | |
147 | ||
148 | if (reg < MONDO_INT_VEC) | |
149 | reg = reg & NCU_INT_MAN_MASK; | |
150 | ||
151 | if (reg >= MONDO_INT_DATA0) { | |
152 | if (UINT64_RANGE_CHECK(MONDO_INT_DATA0, reg, MONDO_INT_DATA1)) | |
153 | reg = MONDO_INT_DATA0; | |
154 | if (UINT64_RANGE_CHECK(MONDO_INT_DATA1, reg, MONDO_INT_ADATA0)) | |
155 | reg = MONDO_INT_DATA1; | |
156 | if (UINT64_RANGE_CHECK(MONDO_INT_ADATA0, reg, MONDO_INT_ADATA1)) | |
157 | reg = MONDO_INT_ADATA0; | |
158 | if (UINT64_RANGE_CHECK(MONDO_INT_ADATA1, reg, MONDO_INT_BUSY)) | |
159 | reg = MONDO_INT_ADATA1; | |
160 | if (UINT64_RANGE_CHECK(MONDO_INT_BUSY, reg, MONDO_INT_ABUSY)) | |
161 | reg = MONDO_INT_BUSY; | |
162 | } | |
163 | ||
164 | //pthread_mutex_lock( &ncu_lock ); | |
165 | ||
166 | uint64_t val; | |
167 | switch(wr){ | |
168 | case true: //8 byte write | |
169 | val = *buf; | |
170 | ||
171 | switch(reg){ | |
172 | case INT_MAN: | |
173 | { | |
174 | int idx; | |
175 | idx = (paddr >> 3) & (NCU_DEV_MAX-1); | |
176 | ASSIGN_NCU(regs.int_man[idx],MASK64(13,8)|MASK64(5,0),val,reg); | |
177 | break; | |
178 | } | |
179 | case MONDO_INT_VEC: | |
180 | ASSIGN_NCU(regs.mondo_int_vec, MASK64(5,0), val, reg); | |
181 | break; | |
182 | case SER_NUM: | |
183 | case EFU_STAT: | |
184 | case CORE_AVAIL: | |
185 | case BANK_AVAIL: | |
186 | case BANK_ENABLE_STATUS: | |
187 | case L2_IDX_HASH_EN_STATUS: | |
188 | case MONDO_INT_DATA0: | |
189 | case MONDO_INT_DATA1: | |
190 | case MONDO_INT_ADATA0: | |
191 | case MONDO_INT_ADATA1: | |
192 | debug_err("%s: attempted write to RO register\n \ | |
193 | Write 0x%llx to register %s (offset 0x%llx\n",\ | |
194 | getName(),val, ncu_reg_name(reg), reg); | |
195 | break; | |
196 | case PCIE_A_MEM32_OFFSET_BASE: | |
197 | ASSIGN_NCU( regs.pcie_a_mem32_offset_base, MASK64(63,63)|MASK64(35,24), val, reg); | |
198 | niagara2_pcie_mapping(PIU_REGION_MEM32); | |
199 | break; | |
200 | case PCIE_A_MEM32_OFFSET_MASK: | |
201 | ASSIGN_NCU( regs.pcie_a_mem32_offset_mask, MASK64(39,24), val, reg); | |
202 | niagara2_pcie_mapping(PIU_REGION_MEM32); | |
203 | break; | |
204 | case PCIE_A_MEM64_OFFSET_BASE: | |
205 | ASSIGN_NCU( regs.pcie_a_mem64_offset_base, MASK64(63,63)|MASK64(35,24), val, reg); | |
206 | niagara2_pcie_mapping(PIU_REGION_MEM64); | |
207 | break; | |
208 | case PCIE_A_MEM64_OFFSET_MASK: | |
209 | ASSIGN_NCU( regs.pcie_a_mem64_offset_mask, MASK64(39,24), val, reg); | |
210 | niagara2_pcie_mapping(PIU_REGION_MEM64); | |
211 | break; | |
212 | case PCIE_A_IOCON_OFFSET_BASE: | |
213 | ASSIGN_NCU( regs.pcie_a_iocon_offset_base, MASK64(63,63)|MASK64(35,24), val, reg ); | |
214 | niagara2_pcie_mapping(PIU_REGION_CFGIO); | |
215 | break; | |
216 | case PCIE_A_IOCON_OFFSET_MASK: | |
217 | ASSIGN_NCU( regs.pcie_a_iocon_offset_mask, MASK64(39,24) ,val, reg ); | |
218 | niagara2_pcie_mapping(PIU_REGION_CFGIO); | |
219 | break; | |
220 | case BANK_ENABLE: | |
221 | case L2_IDX_HASH_EN: | |
222 | debug_more("%s: register %s (offset 0x%llx) not implemented\n", \ | |
223 | getName(),ncu_reg_name(reg), reg); | |
224 | break; | |
225 | case PCIE_A_FSH: | |
226 | ASSIGN_NCU( regs.pcie_a_fsh,~0ULL, val, reg); | |
227 | break; | |
228 | case SOC_ESR: | |
229 | ASSIGN_NCU( regs.soc_esr, MASK64(63,63)|NCU_SOC_MASK, val, reg ); | |
230 | break; | |
231 | case SOC_LOG_ENABLE: | |
232 | ASSIGN_NCU( regs.soc_log_enb, MASK64(42,0) , val, reg ); | |
233 | break; | |
234 | case SOC_INTERRUPT_ENABLE: | |
235 | ASSIGN_NCU( regs.soc_intr_enb, MASK64(42,0), val, reg ); | |
236 | break; | |
237 | case SOC_ERROR_INJECTION: | |
238 | ASSIGN_NCU( regs.soc_err_inject, MASK64(42,0), val, reg ); | |
239 | break; | |
240 | case SOC_FATAL_ERROR_ENABLE: | |
241 | ASSIGN_NCU( regs.soc_fatal_enb, MASK64(42,0), val, reg ); | |
242 | break; | |
243 | case SOC_PENDING_ERROR_STATUS: | |
244 | /* | |
245 | * same as SOC_ESR | |
246 | */ | |
247 | ASSIGN_NCU( regs.soc_esr, MASK64(63,63)|NCU_SOC_MASK, val, reg ); | |
248 | break; | |
249 | case SOC_SII_ERROR_SYNDROME: | |
250 | ASSIGN_NCU( regs.soc_sii_err_syndrome, MASK64(63,63)|MASK64(58,0), val, reg ); | |
251 | break; | |
252 | case SOC_NCU_ERROR_SYNDROME: | |
253 | ASSIGN_NCU( regs.soc_ncu_err_syndrome, MASK64(63,58)|MASK64(55,0), val, reg ); | |
254 | break; | |
255 | case MONDO_INT_BUSY: | |
256 | { | |
257 | int target; | |
258 | target = (paddr >> 3) & (NCU_TARGETS-1); | |
259 | ASSIGN_NCU( regs.mondo_int_busy[target], MASK64(6,6), val, reg ); | |
260 | break; | |
261 | } | |
262 | case MONDO_INT_ABUSY: | |
263 | { | |
264 | int target = cpuid; | |
265 | ASSIGN_NCU( regs.mondo_int_busy[target], MASK64(6,6), val, reg ); | |
266 | break; | |
267 | } | |
268 | default: | |
269 | debug_err("%s: ERROR unknow register access at offset %llx\n",getName(),reg); | |
270 | //pthread_mutex_unlock( &ncu_lock ); | |
271 | return -1; | |
272 | } | |
273 | ||
274 | //debug_more("%s: write at register %s (offset %llx)\n", getName(), ncu_reg_name(reg), val); | |
275 | //pthread_mutex_unlock( &ncu_lock ); | |
276 | return 0; | |
277 | ||
278 | case false: // 8 byte read | |
279 | switch(reg){ | |
280 | case INT_MAN: | |
281 | { | |
282 | int idx; | |
283 | idx = (paddr >> 3) & (NCU_DEV_MAX-1); | |
284 | val = regs.int_man[idx]; | |
285 | break; | |
286 | } | |
287 | case MONDO_INT_VEC: | |
288 | val = regs.mondo_int_vec; | |
289 | break; | |
290 | case SER_NUM: | |
291 | // XXX this ro register becomes a big bottleneck as the cpu | |
292 | // idleloop continuously reads this register. Remove the | |
293 | // locks to reduce contention | |
294 | val = regs.ser_num; | |
295 | // val = 0xdeadbeef; | |
296 | break; | |
297 | case CORE_AVAIL: | |
298 | // XXX need to access the ASI register to provide access. | |
299 | debug_err("%s: ERROR:unimplemented reg read at %s",getName(),ncu_reg_name(reg)); | |
300 | break; | |
301 | case EFU_STAT: | |
302 | val = regs.efu_stat; | |
303 | break; | |
304 | case BANK_AVAIL: | |
305 | case BANK_ENABLE: | |
306 | val = regs.bank_enb; | |
307 | break; | |
308 | case BANK_ENABLE_STATUS: | |
309 | val = regs.bank_enb_stat; | |
310 | break; | |
311 | case PCIE_A_MEM32_OFFSET_BASE: | |
312 | val = regs.pcie_a_mem32_offset_base; | |
313 | break; | |
314 | case PCIE_A_MEM32_OFFSET_MASK: | |
315 | val = regs.pcie_a_mem32_offset_mask; | |
316 | break; | |
317 | case PCIE_A_MEM64_OFFSET_BASE: | |
318 | val = regs.pcie_a_mem64_offset_base; | |
319 | break; | |
320 | case PCIE_A_MEM64_OFFSET_MASK: | |
321 | val = regs.pcie_a_mem64_offset_mask; | |
322 | break; | |
323 | case PCIE_A_IOCON_OFFSET_BASE: | |
324 | val = regs.pcie_a_iocon_offset_base; | |
325 | break; | |
326 | case PCIE_A_IOCON_OFFSET_MASK: | |
327 | val = regs.pcie_a_iocon_offset_mask; | |
328 | break; | |
329 | case L2_IDX_HASH_EN: | |
330 | case L2_IDX_HASH_EN_STATUS: | |
331 | debug_more("%s:register %s (offset 0x%llx) not implemented\n", | |
332 | getName(), ncu_reg_name(reg), reg ); | |
333 | val = 0; | |
334 | break; | |
335 | case PCIE_A_FSH: | |
336 | val = regs.pcie_a_fsh; | |
337 | break; | |
338 | case SOC_ESR: | |
339 | val = regs.soc_esr; | |
340 | break; | |
341 | case SOC_LOG_ENABLE: | |
342 | val = regs.soc_log_enb; | |
343 | break; | |
344 | case SOC_INTERRUPT_ENABLE: | |
345 | val = regs.soc_intr_enb; | |
346 | break; | |
347 | case SOC_ERROR_INJECTION: | |
348 | val = regs.soc_err_inject; | |
349 | break; | |
350 | case SOC_FATAL_ERROR_ENABLE: | |
351 | val = regs.soc_fatal_enb; | |
352 | break; | |
353 | case SOC_PENDING_ERROR_STATUS: | |
354 | /* | |
355 | * same as SOC_ESR | |
356 | */ | |
357 | val = regs.soc_esr; | |
358 | break; | |
359 | case SOC_SII_ERROR_SYNDROME: | |
360 | val = regs.soc_sii_err_syndrome; | |
361 | break; | |
362 | case SOC_NCU_ERROR_SYNDROME: | |
363 | val = regs.soc_ncu_err_syndrome; | |
364 | break; | |
365 | case MONDO_INT_DATA0: | |
366 | { | |
367 | int target = (paddr >> 3) & (NCU_TARGETS-1); | |
368 | val = regs.mondo_int_data0[target]; | |
369 | break; | |
370 | } | |
371 | case MONDO_INT_DATA1: | |
372 | { | |
373 | int target = (paddr >> 3) & (NCU_TARGETS-1); | |
374 | val = regs.mondo_int_data1[target]; | |
375 | break; | |
376 | } | |
377 | case MONDO_INT_ADATA0: | |
378 | { | |
379 | int target = cpuid; | |
380 | val = regs.mondo_int_data0[target]; | |
381 | break; | |
382 | } | |
383 | case MONDO_INT_ADATA1: | |
384 | { | |
385 | int target = cpuid; | |
386 | val = regs.mondo_int_data1[target]; | |
387 | break; | |
388 | } | |
389 | case MONDO_INT_BUSY: | |
390 | { | |
391 | int target = (paddr >> 3) & (NCU_TARGETS-1); | |
392 | val = regs.mondo_int_busy[target]; | |
393 | break; | |
394 | } | |
395 | case MONDO_INT_ABUSY: | |
396 | { | |
397 | int target = cpuid; | |
398 | val = regs.mondo_int_busy[target]; | |
399 | break; | |
400 | } | |
401 | default: | |
402 | *buf = 0; | |
403 | debug_err("%s: ERROR unknow read register access at offset %llx\n",getName(),reg); | |
404 | //pthread_mutex_unlock( &ncu_lock ); | |
405 | return -1; | |
406 | } | |
407 | ||
408 | *buf = val; | |
409 | debug_more("%s: read register %s (value 0x%llx)\n", getName(), ncu_reg_name(reg), val); | |
410 | //pthread_mutex_unlock( &ncu_lock ); | |
411 | return 0; | |
412 | ||
413 | default: | |
414 | *buf = 0; | |
415 | //pthread_mutex_unlock( &ncu_lock ); | |
416 | return -1; | |
417 | } | |
418 | } | |
419 | ||
420 | ||
421 | ||
422 | /* | |
423 | * Create address mapping to access PCIE Cfg/IO, MEM32 and MEM64 space | |
424 | */ | |
425 | void n2Ncu::niagara2_pcie_mapping(piu_region_t region){ | |
426 | uint64_t base, mask, size; | |
427 | bool enable; | |
428 | const char *name[3] = {"Cfg/IO", "Mem32", "Mem64"}; | |
429 | ||
430 | switch(region){ | |
431 | case PIU_REGION_CFGIO: | |
432 | base = regs.pcie_a_iocon_offset_base; | |
433 | mask = regs.pcie_a_iocon_offset_mask; | |
434 | break; | |
435 | case PIU_REGION_MEM32: | |
436 | base = regs.pcie_a_mem32_offset_base; | |
437 | mask = regs.pcie_a_mem32_offset_mask; | |
438 | break; | |
439 | case PIU_REGION_MEM64: | |
440 | base = regs.pcie_a_mem64_offset_base; | |
441 | mask = regs.pcie_a_mem64_offset_mask; | |
442 | break; | |
443 | default: | |
444 | assert(0); | |
445 | } | |
446 | ||
447 | ||
448 | enable = GETMASK64(base,63,63); | |
449 | base &= PIU_REGION_OFFSET_MASK; | |
450 | mask &= PIU_REGION_OFFSET_MASK; | |
451 | ||
452 | if(enable){ | |
453 | size = ~(MASK64(63,36)|mask) + 1; | |
454 | map[region].base = base; | |
455 | map[region].mask = mask; | |
456 | map[region].size = size; | |
457 | map[region].enable = enable; | |
458 | ||
459 | debug_more("%s:PCIE %s is mapped at 0x%llx - 0x%llx\n", \ | |
460 | getName(),name[region],base,base+size-1); | |
461 | } | |
462 | } | |
463 | ||
464 | bool n2Ncu::dump_v1(FILE * fp){ | |
465 | const char * dump_version = "v1.0"; | |
466 | fwrite(dump_version,strlen(dump_version),1,fp); | |
467 | fwrite("\n",strlen("\n"),1,fp); | |
468 | ||
469 | for(int i = 0; i < (sizeof(dumpRegsV1)/sizeof(uint64_t)); i++ ){ | |
470 | char buf[64 * 1024], tcptr[64 * 1024]; | |
471 | sprintf(buf,"%-50s0x%-8llx ",ncu_reg_name(dumpRegsV1[i]),dumpRegsV1[i]); | |
472 | uint64_t base = dumpRegsV1[i]; | |
473 | uint64_t val = 0; | |
474 | switch(dumpRegsV1[i]){ | |
475 | case INT_MAN: | |
476 | for(int j = 0; j < NCU_DEV_MAX; j++){ | |
477 | access_regs(0,base + j*8, mmi_false, 8, &val,0xff); | |
478 | sprintf(tcptr, "0x%04x 0x%016llx,",j,val); | |
479 | strcat(buf,tcptr); | |
480 | } | |
481 | break; | |
482 | case MONDO_INT_DATA0: | |
483 | case MONDO_INT_DATA1: | |
484 | case MONDO_INT_BUSY: | |
485 | for(int j = 0; j < NCU_TARGETS; j++){ | |
486 | access_regs(0,base + j*8, mmi_false, 8, &val,0xff); | |
487 | sprintf(tcptr, "0x%04x 0x%016llx,",j,val); | |
488 | strcat(buf,tcptr); | |
489 | } | |
490 | break; | |
491 | default: | |
492 | access_regs(0,base,mmi_false,8,&val,0xff); | |
493 | sprintf(tcptr, "0x%016llx,",val); | |
494 | strcat(buf,tcptr); | |
495 | break; | |
496 | } | |
497 | fwrite(buf,strlen(buf),1,fp); | |
498 | fwrite("\n",strlen("\n"),1,fp); | |
499 | } | |
500 | fflush(fp); | |
501 | if(fp != stderr) | |
502 | fclose(fp); | |
503 | return true; | |
504 | } | |
505 | ||
506 | ||
507 | bool n2Ncu::dump(FILE * fp){ | |
508 | ||
509 | if(!strcmp(current_dump_version,"v1.0")) | |
510 | return dump_v1(fp); | |
511 | else { | |
512 | assert(0); | |
513 | } | |
514 | } | |
515 | ||
516 | bool n2Ncu::restore(FILE * fp){ | |
517 | const int bufsize = 64 * 1024; | |
518 | char buf[bufsize]; | |
519 | fgets(buf,bufsize,fp); | |
520 | ||
521 | buf[strlen(buf)-1] = 0; | |
522 | ||
523 | if(!strcmp(buf,"v1.0")){ | |
524 | return restore_v1(fp); | |
525 | }else{ | |
526 | printf("%s restore: dump version mismatch, restore failed\n",getName()); | |
527 | return false; | |
528 | } | |
529 | } | |
530 | ||
531 | // if the CSR offsets change, this function may need change as well | |
532 | bool n2Ncu::restore_v1(FILE * fp){ | |
533 | const int bufsize = 64 * 1024; | |
534 | char buf[bufsize]; | |
535 | ||
536 | while(fgets(buf,bufsize,fp)){ | |
537 | strtok(buf," "); // csr name, ignore | |
538 | const char * csr_offset = strtok(0," "); // csr offset | |
539 | uint64_t offset = strtoull(csr_offset,0,0); | |
540 | switch(offset){ | |
541 | case INT_MAN: | |
542 | for(int j = 0; j < NCU_DEV_MAX; j++){ | |
543 | const char * csr_index = strtok(0," "); | |
544 | uint64_t index = strtoull(csr_index,0,0); | |
545 | const char * csr_val = strtok(0,","); | |
546 | uint64_t val = strtoull(csr_val,0,0); | |
547 | regs.int_man[index] = val; | |
548 | } | |
549 | break; | |
550 | case MONDO_INT_DATA0: | |
551 | for(int j = 0; j < NCU_TARGETS; j++){ | |
552 | const char * csr_index = strtok(0," "); | |
553 | uint64_t index = strtoull(csr_index,0,0); | |
554 | const char * csr_val = strtok(0,","); | |
555 | uint64_t val = strtoull(csr_val,0,0); | |
556 | regs.mondo_int_data0[index] = val; | |
557 | } | |
558 | break; | |
559 | case MONDO_INT_DATA1: | |
560 | for(int j = 0; j < NCU_TARGETS; j++){ | |
561 | const char * csr_index = strtok(0," "); | |
562 | uint64_t index = strtoull(csr_index,0,0); | |
563 | const char * csr_val = strtok(0,","); | |
564 | uint64_t val = strtoull(csr_val,0,0); | |
565 | regs.mondo_int_data1[index] = val; | |
566 | } | |
567 | break; | |
568 | case MONDO_INT_BUSY: | |
569 | for(int j = 0; j < NCU_TARGETS; j++){ | |
570 | const char * csr_index = strtok(0," "); | |
571 | uint64_t index = strtoull(csr_index,0,0); | |
572 | const char * csr_val = strtok(0,","); | |
573 | uint64_t val = strtoull(csr_val,0,0); | |
574 | regs.mondo_int_busy[index] = val; | |
575 | } | |
576 | break; | |
577 | case MONDO_INT_VEC: | |
578 | case PCIE_A_MEM32_OFFSET_BASE: | |
579 | case PCIE_A_MEM32_OFFSET_MASK: | |
580 | case PCIE_A_MEM64_OFFSET_BASE: | |
581 | case PCIE_A_MEM64_OFFSET_MASK: | |
582 | case PCIE_A_IOCON_OFFSET_BASE: | |
583 | case PCIE_A_IOCON_OFFSET_MASK: | |
584 | case BANK_ENABLE: | |
585 | case L2_IDX_HASH_EN: | |
586 | case PCIE_A_FSH: | |
587 | case SOC_ESR: | |
588 | case SOC_LOG_ENABLE: | |
589 | case SOC_INTERRUPT_ENABLE: | |
590 | case SOC_ERROR_INJECTION: | |
591 | case SOC_FATAL_ERROR_ENABLE: | |
592 | case SOC_SII_ERROR_SYNDROME: | |
593 | case SOC_NCU_ERROR_SYNDROME: | |
594 | { | |
595 | const char * csr_val = strtok(0,","); | |
596 | uint64_t val = strtoull(csr_val,0,0); | |
597 | access_regs(0,offset,mmi_true,8,&val,0xff); | |
598 | } | |
599 | break; | |
600 | // r/o registers | |
601 | ||
602 | case SER_NUM: | |
603 | { | |
604 | const char * csr_val = strtok(0,","); | |
605 | uint64_t val = strtoull(csr_val,0,0); | |
606 | regs.ser_num = val; | |
607 | break; | |
608 | } | |
609 | case EFU_STAT: | |
610 | { | |
611 | const char * csr_val = strtok(0,","); | |
612 | uint64_t val = strtoull(csr_val,0,0); | |
613 | regs.efu_stat = val; | |
614 | break; | |
615 | } | |
616 | case BANK_ENABLE_STATUS: | |
617 | { | |
618 | const char * csr_val = strtok(0,","); | |
619 | uint64_t val = strtoull(csr_val,0,0); | |
620 | regs.bank_enb_stat = val; | |
621 | break; | |
622 | } | |
623 | case L2_IDX_HASH_EN_STATUS: | |
624 | { | |
625 | const char * csr_val = strtok(0,","); | |
626 | uint64_t val = strtoull(csr_val,0,0); | |
627 | regs.l2_idx_hash_en_stat = val; | |
628 | break; | |
629 | } | |
630 | default: | |
631 | assert(0); | |
632 | } | |
633 | } | |
634 | return true; | |
635 | } | |
636 | ||
637 | void n2Ncu::handle_ui(int argc, char * argv[]){ | |
638 | if(argc == 1){ | |
639 | ui_cmd_usage(); | |
640 | return; | |
641 | }else if(!strcmp(argv[1],"dump")){ | |
642 | FILE * fp = stderr; | |
643 | if(argv[2]){ | |
644 | fp = fopen(argv[2],"w"); | |
645 | if(!fp){ | |
646 | printf("%s dump: error opening file <%s>\n",getName(),argv[2]); | |
647 | fp = stderr; | |
648 | } | |
649 | } | |
650 | dump(fp); | |
651 | }else if(!strcmp(argv[1],"restore")){ | |
652 | FILE * fp; | |
653 | if(argv[2]){ | |
654 | fp = fopen(argv[2],"r"); | |
655 | if(fp) | |
656 | restore(fp); | |
657 | else | |
658 | printf("%s restore: error opening file <%s>\n",getName(),argv[2]); | |
659 | }else | |
660 | printf("%s restore: no restore filename specified\n",getName()); | |
661 | }else if(!strcmp(argv[1],"debug")){ | |
662 | if(argv[2]){ | |
663 | debug_level = atoi(argv[2]); | |
664 | printf("%s: set debug level to %d\n",getName(),debug_level); | |
665 | }else | |
666 | printf("%s: current debug level %d\n",getName(),debug_level); | |
667 | }else | |
668 | debug_err("%s: unsupported UI command <%s>\n",getName(),argv[1]); | |
669 | return; | |
670 | } | |
671 | ||
672 | const char *n2Ncu::ncu_reg_name(uint64_t reg){ | |
673 | ||
674 | switch (reg) { | |
675 | case INT_MAN: return "int_man"; | |
676 | case MONDO_INT_VEC: return "mondo_int_vec"; | |
677 | case SER_NUM: return "ser_num"; | |
678 | case EFU_STAT: return "efu_stat"; | |
679 | case CORE_AVAIL: return "core_avail"; | |
680 | case BANK_AVAIL: return "bank_avail"; | |
681 | case BANK_ENABLE: return "bank_enable"; | |
682 | case BANK_ENABLE_STATUS: return "bank_enable_status"; | |
683 | case L2_IDX_HASH_EN: return "l2_idx_hash_en"; | |
684 | case L2_IDX_HASH_EN_STATUS: return "l2_idx_hash_en_status"; | |
685 | case PCIE_A_MEM32_OFFSET_BASE: return "pcie_a_mem32_offset_base"; | |
686 | case PCIE_A_MEM32_OFFSET_MASK: return "pcie_a_mem32_offset_mask"; | |
687 | case PCIE_A_MEM64_OFFSET_BASE: return "pcie_a_mem64_offset_base"; | |
688 | case PCIE_A_MEM64_OFFSET_MASK: return "pcie_a_mem64_offset_mask"; | |
689 | case PCIE_A_IOCON_OFFSET_BASE: return "pcie_a_iocon_offset_base"; | |
690 | case PCIE_A_IOCON_OFFSET_MASK: return "pcie_a_iocon_offset_mask"; | |
691 | case PCIE_A_FSH: return "pcie_a_fsh"; | |
692 | case SOC_ESR: return "soc_error_status"; | |
693 | case SOC_LOG_ENABLE: return "soc_error_log_enable"; | |
694 | case SOC_INTERRUPT_ENABLE: return "soc_error_interrupt_enable"; | |
695 | case SOC_FATAL_ERROR_ENABLE: return "soc_fatal_error_enable"; | |
696 | case SOC_PENDING_ERROR_STATUS: return "soc_pending_error_status"; | |
697 | case SOC_ERROR_INJECTION: return "soc_error_injection"; | |
698 | case SOC_SII_ERROR_SYNDROME: return "soc_sii_error_syndrome"; | |
699 | case SOC_NCU_ERROR_SYNDROME: return "soc_sii_error_syndrome"; | |
700 | case MONDO_INT_DATA0: return "mondo_int_data0"; | |
701 | case MONDO_INT_DATA1: return "mondo_int_data1"; | |
702 | case MONDO_INT_ADATA0: return "mondo_int_adata0"; | |
703 | case MONDO_INT_ADATA1: return "mondo_int_adata1"; | |
704 | case MONDO_INT_BUSY: return "mondo_int_busy"; | |
705 | case MONDO_INT_ABUSY: return "mondo_int_abusy"; | |
706 | default: return "Illegal NCU register"; | |
707 | } | |
708 | } | |
709 | ||
710 |