b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | /****************************************************************************** |
| 2 | ** |
| 3 | ** FILE NAME : ifxmips_ptm_vdsl.c |
| 4 | ** PROJECT : UEIP |
| 5 | ** MODULES : PTM |
| 6 | ** |
| 7 | ** DATE : 7 Jul 2009 |
| 8 | ** AUTHOR : Xu Liang |
| 9 | ** DESCRIPTION : PTM driver common source file (core functions for VR9) |
| 10 | ** COPYRIGHT : Copyright (c) 2006 |
| 11 | ** Infineon Technologies AG |
| 12 | ** Am Campeon 1-12, 85579 Neubiberg, Germany |
| 13 | ** |
| 14 | ** This program is free software; you can redistribute it and/or modify |
| 15 | ** it under the terms of the GNU General Public License as published by |
| 16 | ** the Free Software Foundation; either version 2 of the License, or |
| 17 | ** (at your option) any later version. |
| 18 | ** |
| 19 | ** HISTORY |
| 20 | ** $Date $Author $Comment |
| 21 | ** 07 JUL 2009 Xu Liang Init Version |
| 22 | *******************************************************************************/ |
| 23 | |
| 24 | |
| 25 | |
| 26 | #ifdef CONFIG_IFX_PTM_TEST_PROC |
| 27 | |
| 28 | /* |
| 29 | * #################################### |
| 30 | * Head File |
| 31 | * #################################### |
| 32 | */ |
| 33 | |
| 34 | /* |
| 35 | * Common Head File |
| 36 | */ |
| 37 | #include <linux/kernel.h> |
| 38 | #include <linux/module.h> |
| 39 | #include <linux/version.h> |
| 40 | #include <linux/types.h> |
| 41 | #include <linux/errno.h> |
| 42 | #include <linux/proc_fs.h> |
| 43 | #include <linux/init.h> |
| 44 | #include <linux/ioctl.h> |
| 45 | #include <linux/etherdevice.h> |
| 46 | |
| 47 | /* |
| 48 | * Chip Specific Head File |
| 49 | */ |
| 50 | #include <asm/ifx/ifx_types.h> |
| 51 | #include <asm/ifx/ifx_regs.h> |
| 52 | #include <asm/ifx/common_routines.h> |
| 53 | #include "ifxmips_ptm_common.h" |
| 54 | #include "ifxmips_ptm_ppe_common.h" |
| 55 | |
| 56 | |
| 57 | |
| 58 | /* |
| 59 | * #################################### |
| 60 | * Definition |
| 61 | * #################################### |
| 62 | */ |
| 63 | |
| 64 | |
| 65 | |
| 66 | /* |
| 67 | * #################################### |
| 68 | * Declaration |
| 69 | * #################################### |
| 70 | */ |
| 71 | |
| 72 | /* |
| 73 | * Proc File Functions |
| 74 | */ |
| 75 | static inline void proc_file_create(void); |
| 76 | static inline void proc_file_delete(void); |
| 77 | |
| 78 | /* |
| 79 | * Proc Help Functions |
| 80 | */ |
| 81 | static int proc_write_mem(struct file *, const char *, unsigned long, void *); |
| 82 | static int proc_read_pp32(char *, char **, off_t, int, int *, void *); |
| 83 | static int proc_write_pp32(struct file *, const char *, unsigned long, void *); |
| 84 | static int stricmp(const char *, const char *); |
| 85 | static int strincmp(const char *, const char *, int); |
| 86 | static int get_token(char **, char **, int *, int *); |
| 87 | static int get_number(char **, int *, int); |
| 88 | static inline void ignore_space(char **, int *); |
| 89 | |
| 90 | |
| 91 | |
| 92 | /* |
| 93 | * #################################### |
| 94 | * Local Variable |
| 95 | * #################################### |
| 96 | */ |
| 97 | |
| 98 | |
| 99 | |
| 100 | /* |
| 101 | * #################################### |
| 102 | * Local Function |
| 103 | * #################################### |
| 104 | */ |
| 105 | |
| 106 | static inline void proc_file_create(void) |
| 107 | { |
| 108 | struct proc_dir_entry *res; |
| 109 | |
| 110 | res = create_proc_entry("driver/ifx_ptm/mem", |
| 111 | 0, |
| 112 | NULL); |
| 113 | if ( res != NULL ) |
| 114 | res->write_proc = proc_write_mem; |
| 115 | else |
| 116 | printk("%s:%s:%d: failed to create proc mem!", __FILE__, __func__, __LINE__); |
| 117 | |
| 118 | res = create_proc_entry("driver/ifx_ptm/pp32", |
| 119 | 0, |
| 120 | NULL); |
| 121 | if ( res != NULL ) { |
| 122 | res->read_proc = proc_read_pp32; |
| 123 | res->write_proc = proc_write_pp32; |
| 124 | } |
| 125 | else |
| 126 | printk("%s:%s:%d: failed to create proc pp32!", __FILE__, __func__, __LINE__); |
| 127 | } |
| 128 | |
| 129 | static inline void proc_file_delete(void) |
| 130 | { |
| 131 | remove_proc_entry("driver/ifx_ptm/pp32", NULL); |
| 132 | |
| 133 | remove_proc_entry("driver/ifx_ptm/mem", NULL); |
| 134 | } |
| 135 | |
| 136 | static inline unsigned long sb_addr_to_fpi_addr_convert(unsigned long sb_addr) |
| 137 | { |
| 138 | #define PP32_SB_ADDR_END 0xFFFF |
| 139 | |
| 140 | if ( sb_addr < PP32_SB_ADDR_END) { |
| 141 | return (unsigned long ) SB_BUFFER(sb_addr); |
| 142 | } |
| 143 | else { |
| 144 | return sb_addr; |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | static int proc_write_mem(struct file *file, const char *buf, unsigned long count, void *data) |
| 149 | { |
| 150 | char *p1, *p2; |
| 151 | int len; |
| 152 | int colon; |
| 153 | unsigned long *p; |
| 154 | char local_buf[1024]; |
| 155 | int i, n, l; |
| 156 | |
| 157 | len = sizeof(local_buf) < count ? sizeof(local_buf) - 1 : count; |
| 158 | len = len - copy_from_user(local_buf, buf, len); |
| 159 | local_buf[len] = 0; |
| 160 | |
| 161 | p1 = local_buf; |
| 162 | colon = 1; |
| 163 | while ( get_token(&p1, &p2, &len, &colon) ) |
| 164 | { |
| 165 | if ( stricmp(p1, "w") == 0 || stricmp(p1, "write") == 0 || stricmp(p1, "r") == 0 || stricmp(p1, "read") == 0 ) |
| 166 | break; |
| 167 | |
| 168 | p1 = p2; |
| 169 | colon = 1; |
| 170 | } |
| 171 | |
| 172 | if ( *p1 == 'w' ) |
| 173 | { |
| 174 | ignore_space(&p2, &len); |
| 175 | p = (unsigned long *)get_number(&p2, &len, 1); |
| 176 | p = (unsigned long *)sb_addr_to_fpi_addr_convert( (unsigned long) p); |
| 177 | |
| 178 | if ( (u32)p >= KSEG0 ) |
| 179 | while ( 1 ) |
| 180 | { |
| 181 | ignore_space(&p2, &len); |
| 182 | if ( !len || !((*p2 >= '0' && *p2 <= '9') || (*p2 >= 'a' && *p2 <= 'f') || (*p2 >= 'A' && *p2 <= 'F')) ) |
| 183 | break; |
| 184 | |
| 185 | *p++ = (u32)get_number(&p2, &len, 1); |
| 186 | } |
| 187 | } |
| 188 | else if ( *p1 == 'r' ) |
| 189 | { |
| 190 | ignore_space(&p2, &len); |
| 191 | p = (unsigned long *)get_number(&p2, &len, 1); |
| 192 | p = (unsigned long *)sb_addr_to_fpi_addr_convert( (unsigned long) p); |
| 193 | |
| 194 | if ( (u32)p >= KSEG0 ) |
| 195 | { |
| 196 | ignore_space(&p2, &len); |
| 197 | n = (int)get_number(&p2, &len, 0); |
| 198 | if ( n ) |
| 199 | { |
| 200 | char str[32] = {0}; |
| 201 | char *pch = str; |
| 202 | int k; |
| 203 | u32 data; |
| 204 | char c; |
| 205 | |
| 206 | n += (l = ((int)p >> 2) & 0x03); |
| 207 | p = (unsigned long *)((u32)p & ~0x0F); |
| 208 | for ( i = 0; i < n; i++ ) |
| 209 | { |
| 210 | if ( (i & 0x03) == 0 ) |
| 211 | { |
| 212 | printk("%08X:", (u32)p); |
| 213 | pch = str; |
| 214 | } |
| 215 | if ( i < l ) |
| 216 | { |
| 217 | printk(" "); |
| 218 | sprintf(pch, " "); |
| 219 | } |
| 220 | else |
| 221 | { |
| 222 | data = (u32)*p; |
| 223 | printk(" %08X", data); |
| 224 | for ( k = 0; k < 4; k++ ) |
| 225 | { |
| 226 | c = ((char*)&data)[k]; |
| 227 | pch[k] = c < ' ' ? '.' : c; |
| 228 | } |
| 229 | } |
| 230 | p++; |
| 231 | pch += 4; |
| 232 | if ( (i & 0x03) == 0x03 ) |
| 233 | { |
| 234 | pch[0] = 0; |
| 235 | printk(" ; %s\n", str); |
| 236 | } |
| 237 | } |
| 238 | if ( (n & 0x03) != 0x00 ) |
| 239 | { |
| 240 | for ( k = 4 - (n & 0x03); k > 0; k-- ) |
| 241 | printk(" "); |
| 242 | pch[0] = 0; |
| 243 | printk(" ; %s\n", str); |
| 244 | } |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 | |
| 249 | return count; |
| 250 | } |
| 251 | |
| 252 | #ifdef CONFIG_DANUBE |
| 253 | |
| 254 | static int proc_read_pp32(char *page, char **start, off_t off, int count, int *eof, void *data) |
| 255 | { |
| 256 | static const char *halt_stat[] = { |
| 257 | "reset", |
| 258 | "break in line", |
| 259 | "stop", |
| 260 | "step", |
| 261 | "code", |
| 262 | "data0", |
| 263 | "data1" |
| 264 | }; |
| 265 | static const char *brk_src_data[] = { |
| 266 | "off", |
| 267 | "read", |
| 268 | "write", |
| 269 | "read/write", |
| 270 | "write_equal", |
| 271 | "N/A", |
| 272 | "N/A", |
| 273 | "N/A" |
| 274 | }; |
| 275 | static const char *brk_src_code[] = { |
| 276 | "off", |
| 277 | "on" |
| 278 | }; |
| 279 | |
| 280 | int len = 0; |
| 281 | int cur_task; |
| 282 | int i, j; |
| 283 | int k; |
| 284 | unsigned long bit; |
| 285 | |
| 286 | len += sprintf(page + off + len, "Task No %d, PC %04x\n", *PP32_DBG_TASK_NO & 0x03, *PP32_DBG_CUR_PC & 0xFFFF); |
| 287 | |
| 288 | if ( !(*PP32_HALT_STAT & 0x01) ) |
| 289 | len += sprintf(page + off + len, " Halt State: Running\n"); |
| 290 | else |
| 291 | { |
| 292 | len += sprintf(page + off + len, " Halt State: Stopped"); |
| 293 | k = 0; |
| 294 | for ( bit = 2, i = 0; bit <= (1 << 7); bit <<= 1, i++ ) |
| 295 | if ( (*PP32_HALT_STAT & bit) ) |
| 296 | { |
| 297 | if ( !k ) |
| 298 | { |
| 299 | len += sprintf(page + off + len, ", "); |
| 300 | k++; |
| 301 | } |
| 302 | else |
| 303 | len += sprintf(page + off + len, " | "); |
| 304 | len += sprintf(page + off + len, halt_stat[i]); |
| 305 | } |
| 306 | |
| 307 | len += sprintf(page + off + len, "\n"); |
| 308 | |
| 309 | cur_task = *PP32_DBG_TASK_NO & 0x03; |
| 310 | len += sprintf(page + off + len, "General Purpose Register (Task %d):\n", cur_task); |
| 311 | for ( i = 0; i < 4; i++ ) |
| 312 | { |
| 313 | for ( j = 0; j < 4; j++ ) |
| 314 | len += sprintf(page + off + len, " %2d: %08x", i + j * 4, *PP32_DBG_TASK_GPR(cur_task, i + j * 4)); |
| 315 | len += sprintf(page + off + len, "\n"); |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | len += sprintf(page + off + len, " Break Src: data1 - %s, data0 - %s, pc3 - %s, pc2 - %s, pc1 - %s, pc0 - %s\n", |
| 320 | brk_src_data[(*PP32_BRK_SRC >> 11) & 0x07], brk_src_data[(*PP32_BRK_SRC >> 8) & 0x07], brk_src_code[(*PP32_BRK_SRC >> 3) & 0x01], brk_src_code[(*PP32_BRK_SRC >> 2) & 0x01], brk_src_code[(*PP32_BRK_SRC >> 1) & 0x01], brk_src_code[*PP32_BRK_SRC & 0x01]); |
| 321 | |
| 322 | for ( i = 0; i < 4; i++ ) |
| 323 | len += sprintf(page + off + len, " pc%d: %04x - %04x\n", i, *PP32_DBG_PC_MIN(i), *PP32_DBG_PC_MAX(i)); |
| 324 | |
| 325 | for ( i = 0; i < 2; i++ ) |
| 326 | len += sprintf(page + off + len, " data%d: %04x - %04x (%08x)\n", i, *PP32_DBG_DATA_MIN(i), *PP32_DBG_DATA_MAX(i), *PP32_DBG_DATA_VAL(i)); |
| 327 | |
| 328 | *eof = 1; |
| 329 | |
| 330 | return len; |
| 331 | } |
| 332 | |
| 333 | static int proc_write_pp32(struct file *file, const char *buf, unsigned long count, void *data) |
| 334 | { |
| 335 | char str[2048]; |
| 336 | char *p; |
| 337 | int len, rlen; |
| 338 | |
| 339 | int id; |
| 340 | u32 addr; |
| 341 | u32 cmd; |
| 342 | |
| 343 | len = count < sizeof(str) ? count : sizeof(str) - 1; |
| 344 | rlen = len - copy_from_user(str, buf, len); |
| 345 | while ( rlen && str[rlen - 1] <= ' ' ) |
| 346 | rlen--; |
| 347 | str[rlen] = 0; |
| 348 | for ( p = str; *p && *p <= ' '; p++, rlen-- ); |
| 349 | if ( !*p ) |
| 350 | { |
| 351 | return 0; |
| 352 | } |
| 353 | |
| 354 | if ( stricmp(str, "start") == 0 ) |
| 355 | *PP32_DBG_CTRL = DBG_CTRL_START_SET(1); |
| 356 | else if ( stricmp(str, "stop") == 0 ) |
| 357 | *PP32_DBG_CTRL = DBG_CTRL_STOP_SET(1); |
| 358 | else if ( stricmp(str, "step") == 0 ) |
| 359 | *PP32_DBG_CTRL = DBG_CTRL_STEP_SET(1); |
| 360 | else if ( strincmp(p, "pc", 2) == 0 && p[2] >= '0' && p[2] <= '3' && p[3] == ' ' ) |
| 361 | { |
| 362 | id = (int)(p[2] - '0'); |
| 363 | p += 4; |
| 364 | rlen -= 4; |
| 365 | *PP32_BRK_SRC &= ~PP32_BRK_SRC_PC(id); |
| 366 | if ( stricmp(p, "off") != 0 ) |
| 367 | { |
| 368 | ignore_space(&p, &rlen); |
| 369 | *PP32_DBG_PC_MIN(id) = *PP32_DBG_PC_MAX(id) = get_number(&p, &rlen, 1); |
| 370 | ignore_space(&p, &rlen); |
| 371 | if ( rlen > 0 ) |
| 372 | { |
| 373 | addr = get_number(&p, &rlen, 1); |
| 374 | if ( addr >= *PP32_DBG_PC_MIN(id) ) |
| 375 | *PP32_DBG_PC_MAX(id) = addr; |
| 376 | else |
| 377 | *PP32_DBG_PC_MIN(id) = addr; |
| 378 | } |
| 379 | *PP32_BRK_SRC |= PP32_BRK_SRC_PC(id); |
| 380 | } |
| 381 | } |
| 382 | else if ( strincmp(p, "daddr", 5) == 0 && p[5] >= '0' && p[5] <= '1' && p[6] == ' ' ) |
| 383 | { |
| 384 | id = (int)(p[5] - '0'); |
| 385 | p += 7; |
| 386 | rlen -= 7; |
| 387 | *PP32_BRK_SRC &= ~PP32_BRK_SRC_DATA(id, 7); |
| 388 | if ( stricmp(p, "off") != 0 ) |
| 389 | { |
| 390 | ignore_space(&p, &rlen); |
| 391 | *PP32_DBG_DATA_MIN(id) = *PP32_DBG_DATA_MAX(id) = get_number(&p, &rlen, 1); |
| 392 | cmd = 1; |
| 393 | ignore_space(&p, &rlen); |
| 394 | if ( rlen > 0 && ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')) ) |
| 395 | { |
| 396 | addr = get_number(&p, &rlen, 1); |
| 397 | if ( addr >= *PP32_DBG_PC_MIN(id) ) |
| 398 | *PP32_DBG_DATA_MAX(id) = addr; |
| 399 | else |
| 400 | *PP32_DBG_DATA_MIN(id) = addr; |
| 401 | ignore_space(&p, &rlen); |
| 402 | } |
| 403 | if ( *p == 'w' ) |
| 404 | cmd = 2; |
| 405 | else if ( *p == 'r' && p[1] == 'w' ) |
| 406 | { |
| 407 | cmd = 3; |
| 408 | p++; |
| 409 | rlen--; |
| 410 | } |
| 411 | p++; |
| 412 | rlen--; |
| 413 | if ( rlen > 0 ) |
| 414 | { |
| 415 | ignore_space(&p, &rlen); |
| 416 | if ( (*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')) |
| 417 | { |
| 418 | *PP32_DBG_DATA_VAL(id) = get_number(&p, &rlen, 1); |
| 419 | cmd = 4; |
| 420 | } |
| 421 | } |
| 422 | *PP32_BRK_SRC |= PP32_BRK_SRC_DATA(id, cmd); |
| 423 | } |
| 424 | } |
| 425 | else |
| 426 | { |
| 427 | printk("echo \"<command>\" > /proc/driver/ifx_ptm/pp32\n"); |
| 428 | printk(" command:\n"); |
| 429 | printk(" start - run pp32\n"); |
| 430 | printk(" stop - stop pp32\n"); |
| 431 | printk(" step - run pp32 with one step only\n"); |
| 432 | printk(" pc0 - pc0 <addr_min [addr_max]>/off, set break point PC0\n"); |
| 433 | printk(" pc1 - pc1 <addr_min [addr_max]>/off, set break point PC1\n"); |
| 434 | printk(" pc2 - pc2 <addr_min [addr_max]>/off, set break point PC2\n"); |
| 435 | printk(" pc3 - pc3 <addr_min [addr_max]>/off, set break point PC3\n"); |
| 436 | printk(" daddr0 - daddr0 <addr_min [addr_max] r/w/rw [value]>/off, set break point data address 0\n"); |
| 437 | printk(" daddr1 - daddr1 <addr_min [addr_max] r/w/rw [value]>/off, set break point data address 1\n"); |
| 438 | printk(" help - print this screen\n"); |
| 439 | } |
| 440 | |
| 441 | return count; |
| 442 | } |
| 443 | |
| 444 | #else |
| 445 | |
| 446 | static int proc_read_pp32(char *page, char **start, off_t off, int count, int *eof, void *data) |
| 447 | { |
| 448 | static const char *stron = " on"; |
| 449 | static const char *stroff = "off"; |
| 450 | |
| 451 | int len = 0; |
| 452 | int cur_context; |
| 453 | int f_stopped; |
| 454 | char str[256]; |
| 455 | char strlength; |
| 456 | int i, j; |
| 457 | |
| 458 | int pp32; |
| 459 | |
| 460 | for ( pp32 = 0; pp32 < NUM_OF_PP32; pp32++ ) |
| 461 | { |
| 462 | f_stopped = 0; |
| 463 | |
| 464 | len += sprintf(page + off + len, "===== pp32 core %d =====\n", pp32); |
| 465 | |
| 466 | #ifdef CONFIG_VR9 |
| 467 | if ( (*PP32_FREEZE & (1 << (pp32 << 4))) != 0 ) |
| 468 | { |
| 469 | sprintf(str, "freezed"); |
| 470 | f_stopped = 1; |
| 471 | } |
| 472 | #else |
| 473 | if ( 0 ) |
| 474 | { |
| 475 | } |
| 476 | #endif |
| 477 | else if ( PP32_CPU_USER_STOPPED(pp32) || PP32_CPU_USER_BREAKIN_RCV(pp32) || PP32_CPU_USER_BREAKPOINT_MET(pp32) ) |
| 478 | { |
| 479 | strlength = 0; |
| 480 | if ( PP32_CPU_USER_STOPPED(pp32) ) |
| 481 | strlength += sprintf(str + strlength, "stopped"); |
| 482 | if ( PP32_CPU_USER_BREAKPOINT_MET(pp32) ) |
| 483 | strlength += sprintf(str + strlength, strlength ? " | breakpoint" : "breakpoint"); |
| 484 | if ( PP32_CPU_USER_BREAKIN_RCV(pp32) ) |
| 485 | strlength += sprintf(str + strlength, strlength ? " | breakin" : "breakin"); |
| 486 | f_stopped = 1; |
| 487 | } |
| 488 | else if ( PP32_CPU_CUR_PC(pp32) == PP32_CPU_CUR_PC(pp32) ) |
| 489 | { |
| 490 | unsigned int pc_value[64] = {0}; |
| 491 | |
| 492 | f_stopped = 1; |
| 493 | for ( i = 0; f_stopped && i < NUM_ENTITY(pc_value); i++ ) |
| 494 | { |
| 495 | pc_value[i] = PP32_CPU_CUR_PC(pp32); |
| 496 | for ( j = 0; j < i; j++ ) |
| 497 | if ( pc_value[j] != pc_value[i] ) |
| 498 | { |
| 499 | f_stopped = 0; |
| 500 | break; |
| 501 | } |
| 502 | } |
| 503 | if ( f_stopped ) |
| 504 | sprintf(str, "hang"); |
| 505 | } |
| 506 | if ( !f_stopped ) |
| 507 | sprintf(str, "running"); |
| 508 | cur_context = PP32_BRK_CUR_CONTEXT(pp32); |
| 509 | len += sprintf(page + off + len, "Context: %d, PC: 0x%04x, %s\n", cur_context, PP32_CPU_CUR_PC(pp32), str); |
| 510 | |
| 511 | if ( PP32_CPU_USER_BREAKPOINT_MET(pp32) ) |
| 512 | { |
| 513 | strlength = 0; |
| 514 | if ( PP32_BRK_PC_MET(pp32, 0) ) |
| 515 | strlength += sprintf(str + strlength, "pc0"); |
| 516 | if ( PP32_BRK_PC_MET(pp32, 1) ) |
| 517 | strlength += sprintf(str + strlength, strlength ? " | pc1" : "pc1"); |
| 518 | if ( PP32_BRK_DATA_ADDR_MET(pp32, 0) ) |
| 519 | strlength += sprintf(str + strlength, strlength ? " | daddr0" : "daddr0"); |
| 520 | if ( PP32_BRK_DATA_ADDR_MET(pp32, 1) ) |
| 521 | strlength += sprintf(str + strlength, strlength ? " | daddr1" : "daddr1"); |
| 522 | if ( PP32_BRK_DATA_VALUE_RD_MET(pp32, 0) ) |
| 523 | { |
| 524 | strlength += sprintf(str + strlength, strlength ? " | rdval0" : "rdval0"); |
| 525 | if ( PP32_BRK_DATA_VALUE_RD_LO_EQ(pp32, 0) ) |
| 526 | { |
| 527 | if ( PP32_BRK_DATA_VALUE_RD_GT_EQ(pp32, 0) ) |
| 528 | strlength += sprintf(str + strlength, " =="); |
| 529 | else |
| 530 | strlength += sprintf(str + strlength, " <="); |
| 531 | } |
| 532 | else if ( PP32_BRK_DATA_VALUE_RD_GT_EQ(pp32, 0) ) |
| 533 | strlength += sprintf(str + strlength, " >="); |
| 534 | } |
| 535 | if ( PP32_BRK_DATA_VALUE_RD_MET(pp32, 1) ) |
| 536 | { |
| 537 | strlength += sprintf(str + strlength, strlength ? " | rdval1" : "rdval1"); |
| 538 | if ( PP32_BRK_DATA_VALUE_RD_LO_EQ(pp32, 1) ) |
| 539 | { |
| 540 | if ( PP32_BRK_DATA_VALUE_RD_GT_EQ(pp32, 1) ) |
| 541 | strlength += sprintf(str + strlength, " =="); |
| 542 | else |
| 543 | strlength += sprintf(str + strlength, " <="); |
| 544 | } |
| 545 | else if ( PP32_BRK_DATA_VALUE_RD_GT_EQ(pp32, 1) ) |
| 546 | strlength += sprintf(str + strlength, " >="); |
| 547 | } |
| 548 | if ( PP32_BRK_DATA_VALUE_WR_MET(pp32, 0) ) |
| 549 | { |
| 550 | strlength += sprintf(str + strlength, strlength ? " | wtval0" : "wtval0"); |
| 551 | if ( PP32_BRK_DATA_VALUE_WR_LO_EQ(pp32, 0) ) |
| 552 | { |
| 553 | if ( PP32_BRK_DATA_VALUE_WR_GT_EQ(pp32, 0) ) |
| 554 | strlength += sprintf(str + strlength, " =="); |
| 555 | else |
| 556 | strlength += sprintf(str + strlength, " <="); |
| 557 | } |
| 558 | else if ( PP32_BRK_DATA_VALUE_WR_GT_EQ(pp32, 0) ) |
| 559 | strlength += sprintf(str + strlength, " >="); |
| 560 | } |
| 561 | if ( PP32_BRK_DATA_VALUE_WR_MET(pp32, 1) ) |
| 562 | { |
| 563 | strlength += sprintf(str + strlength, strlength ? " | wtval1" : "wtval1"); |
| 564 | if ( PP32_BRK_DATA_VALUE_WR_LO_EQ(pp32, 1) ) |
| 565 | { |
| 566 | if ( PP32_BRK_DATA_VALUE_WR_GT_EQ(pp32, 1) ) |
| 567 | strlength += sprintf(str + strlength, " =="); |
| 568 | else |
| 569 | strlength += sprintf(str + strlength, " <="); |
| 570 | } |
| 571 | else if ( PP32_BRK_DATA_VALUE_WR_GT_EQ(pp32, 1) ) |
| 572 | strlength += sprintf(str + strlength, " >="); |
| 573 | } |
| 574 | len += sprintf(page + off + len, "break reason: %s\n", str); |
| 575 | } |
| 576 | |
| 577 | if ( f_stopped ) |
| 578 | { |
| 579 | len += sprintf(page + off + len, "General Purpose Register (Context %d):\n", cur_context); |
| 580 | for ( i = 0; i < 4; i++ ) |
| 581 | { |
| 582 | for ( j = 0; j < 4; j++ ) |
| 583 | len += sprintf(page + off + len, " %2d: %08x", i + j * 4, *PP32_GP_CONTEXTi_REGn(pp32, cur_context, i + j * 4)); |
| 584 | len += sprintf(page + off + len, "\n"); |
| 585 | } |
| 586 | } |
| 587 | |
| 588 | len += sprintf(page + off + len, "break out on: break in - %s, stop - %s\n", |
| 589 | PP32_CTRL_OPT_BREAKOUT_ON_BREAKIN(pp32) ? stron : stroff, |
| 590 | PP32_CTRL_OPT_BREAKOUT_ON_STOP(pp32) ? stron : stroff); |
| 591 | len += sprintf(page + off + len, " stop on: break in - %s, break point - %s\n", |
| 592 | PP32_CTRL_OPT_STOP_ON_BREAKIN(pp32) ? stron : stroff, |
| 593 | PP32_CTRL_OPT_STOP_ON_BREAKPOINT(pp32) ? stron : stroff); |
| 594 | len += sprintf(page + off + len, "breakpoint:\n"); |
| 595 | len += sprintf(page + off + len, " pc0: 0x%08x, %s\n", *PP32_BRK_PC(pp32, 0), PP32_BRK_GRPi_PCn(pp32, 0, 0) ? "group 0" : "off"); |
| 596 | len += sprintf(page + off + len, " pc1: 0x%08x, %s\n", *PP32_BRK_PC(pp32, 1), PP32_BRK_GRPi_PCn(pp32, 1, 1) ? "group 1" : "off"); |
| 597 | len += sprintf(page + off + len, " daddr0: 0x%08x, %s\n", *PP32_BRK_DATA_ADDR(pp32, 0), PP32_BRK_GRPi_DATA_ADDRn(pp32, 0, 0) ? "group 0" : "off"); |
| 598 | len += sprintf(page + off + len, " daddr1: 0x%08x, %s\n", *PP32_BRK_DATA_ADDR(pp32, 1), PP32_BRK_GRPi_DATA_ADDRn(pp32, 1, 1) ? "group 1" : "off"); |
| 599 | len += sprintf(page + off + len, " rdval0: 0x%08x\n", *PP32_BRK_DATA_VALUE_RD(pp32, 0)); |
| 600 | len += sprintf(page + off + len, " rdval1: 0x%08x\n", *PP32_BRK_DATA_VALUE_RD(pp32, 1)); |
| 601 | len += sprintf(page + off + len, " wrval0: 0x%08x\n", *PP32_BRK_DATA_VALUE_WR(pp32, 0)); |
| 602 | len += sprintf(page + off + len, " wrval1: 0x%08x\n", *PP32_BRK_DATA_VALUE_WR(pp32, 1)); |
| 603 | } |
| 604 | |
| 605 | *eof = 1; |
| 606 | |
| 607 | return len; |
| 608 | } |
| 609 | |
| 610 | static int proc_write_pp32(struct file *file, const char *buf, unsigned long count, void *data) |
| 611 | { |
| 612 | char str[2048]; |
| 613 | char *p; |
| 614 | int len, rlen; |
| 615 | |
| 616 | int pp32 = 0; |
| 617 | u32 addr; |
| 618 | |
| 619 | len = count < sizeof(str) ? count : sizeof(str) - 1; |
| 620 | rlen = len - copy_from_user(str, buf, len); |
| 621 | while ( rlen && str[rlen - 1] <= ' ' ) |
| 622 | rlen--; |
| 623 | str[rlen] = 0; |
| 624 | for ( p = str; *p && *p <= ' '; p++, rlen-- ); |
| 625 | if ( !*p ) |
| 626 | return 0; |
| 627 | |
| 628 | if ( strincmp(p, "pp32 ", 5) == 0 ) |
| 629 | { |
| 630 | p += 5; |
| 631 | rlen -= 5; |
| 632 | |
| 633 | while ( rlen > 0 && *p >= '0' && *p <= '9' ) |
| 634 | { |
| 635 | pp32 += *p - '0'; |
| 636 | p++; |
| 637 | rlen--; |
| 638 | } |
| 639 | while ( rlen > 0 && *p && *p <= ' ' ) |
| 640 | { |
| 641 | p++; |
| 642 | rlen--; |
| 643 | } |
| 644 | |
| 645 | if ( pp32 >= NUM_OF_PP32 ) |
| 646 | { |
| 647 | printk(KERN_ERR __FILE__ ":%d:%s: incorrect pp32 index - %d\n", __LINE__, __FUNCTION__, pp32); |
| 648 | return count; |
| 649 | } |
| 650 | } |
| 651 | |
| 652 | if ( stricmp(p, "start") == 0 ) |
| 653 | { |
| 654 | #ifdef CONFIG_AMAZON_SE |
| 655 | *PP32_CTRL_CMD(pp32) = 0; |
| 656 | #endif |
| 657 | *PP32_CTRL_CMD(pp32) = PP32_CTRL_CMD_RESTART; |
| 658 | } |
| 659 | else if ( stricmp(p, "stop") == 0 ) |
| 660 | { |
| 661 | #ifdef CONFIG_AMAZON_SE |
| 662 | *PP32_CTRL_CMD(pp32) = 0; |
| 663 | #endif |
| 664 | *PP32_CTRL_CMD(pp32) = PP32_CTRL_CMD_STOP; |
| 665 | } |
| 666 | else if ( stricmp(p, "step") == 0 ) |
| 667 | { |
| 668 | #ifdef CONFIG_AMAZON_SE |
| 669 | *PP32_CTRL_CMD(pp32) = 0; |
| 670 | #endif |
| 671 | *PP32_CTRL_CMD(pp32) = PP32_CTRL_CMD_STEP; |
| 672 | } |
| 673 | #ifdef CONFIG_VR9 |
| 674 | else if ( stricmp(p, "unfreeze") == 0 ) |
| 675 | *PP32_FREEZE &= ~(1 << (pp32 << 4)); |
| 676 | else if ( stricmp(p, "freeze") == 0 ) |
| 677 | *PP32_FREEZE |= 1 << (pp32 << 4); |
| 678 | #else |
| 679 | else if ( stricmp(p, "unfreeze") == 0 ) |
| 680 | *PP32_DBG_CTRL(pp32) = DBG_CTRL_RESTART; |
| 681 | else if ( stricmp(p, "freeze") == 0 ) |
| 682 | *PP32_DBG_CTRL(pp32) = DBG_CTRL_STOP; |
| 683 | #endif |
| 684 | else if ( strincmp(p, "pc0 ", 4) == 0 ) |
| 685 | { |
| 686 | p += 4; |
| 687 | rlen -= 4; |
| 688 | if ( stricmp(p, "off") == 0 ) |
| 689 | { |
| 690 | *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_PCn_OFF(0, 0); |
| 691 | *PP32_BRK_PC_MASK(pp32, 0) = PP32_BRK_CONTEXT_MASK_EN; |
| 692 | *PP32_BRK_PC(pp32, 0) = 0; |
| 693 | } |
| 694 | else |
| 695 | { |
| 696 | addr = get_number(&p, &rlen, 1); |
| 697 | *PP32_BRK_PC(pp32, 0) = addr; |
| 698 | *PP32_BRK_PC_MASK(pp32, 0) = PP32_BRK_CONTEXT_MASK_EN | PP32_BRK_CONTEXT_MASK(0) | PP32_BRK_CONTEXT_MASK(1) | PP32_BRK_CONTEXT_MASK(2) | PP32_BRK_CONTEXT_MASK(3); |
| 699 | *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_PCn_ON(0, 0); |
| 700 | } |
| 701 | } |
| 702 | else if ( strincmp(p, "pc1 ", 4) == 0 ) |
| 703 | { |
| 704 | p += 4; |
| 705 | rlen -= 4; |
| 706 | if ( stricmp(p, "off") == 0 ) |
| 707 | { |
| 708 | *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_PCn_OFF(1, 1); |
| 709 | *PP32_BRK_PC_MASK(pp32, 1) = PP32_BRK_CONTEXT_MASK_EN; |
| 710 | *PP32_BRK_PC(pp32, 1) = 0; |
| 711 | } |
| 712 | else |
| 713 | { |
| 714 | addr = get_number(&p, &rlen, 1); |
| 715 | *PP32_BRK_PC(pp32, 1) = addr; |
| 716 | *PP32_BRK_PC_MASK(pp32, 1) = PP32_BRK_CONTEXT_MASK_EN | PP32_BRK_CONTEXT_MASK(0) | PP32_BRK_CONTEXT_MASK(1) | PP32_BRK_CONTEXT_MASK(2) | PP32_BRK_CONTEXT_MASK(3); |
| 717 | *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_PCn_ON(1, 1); |
| 718 | } |
| 719 | } |
| 720 | else if ( strincmp(p, "daddr0 ", 7) == 0 ) |
| 721 | { |
| 722 | p += 7; |
| 723 | rlen -= 7; |
| 724 | if ( stricmp(p, "off") == 0 ) |
| 725 | { |
| 726 | *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_DATA_ADDRn_OFF(0, 0); |
| 727 | *PP32_BRK_DATA_ADDR_MASK(pp32, 0) = PP32_BRK_CONTEXT_MASK_EN; |
| 728 | *PP32_BRK_DATA_ADDR(pp32, 0) = 0; |
| 729 | } |
| 730 | else |
| 731 | { |
| 732 | addr = get_number(&p, &rlen, 1); |
| 733 | *PP32_BRK_DATA_ADDR(pp32, 0) = addr; |
| 734 | *PP32_BRK_DATA_ADDR_MASK(pp32, 0) = PP32_BRK_CONTEXT_MASK_EN | PP32_BRK_CONTEXT_MASK(0) | PP32_BRK_CONTEXT_MASK(1) | PP32_BRK_CONTEXT_MASK(2) | PP32_BRK_CONTEXT_MASK(3); |
| 735 | *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_DATA_ADDRn_ON(0, 0); |
| 736 | } |
| 737 | } |
| 738 | else if ( strincmp(p, "daddr1 ", 7) == 0 ) |
| 739 | { |
| 740 | p += 7; |
| 741 | rlen -= 7; |
| 742 | if ( stricmp(p, "off") == 0 ) |
| 743 | { |
| 744 | *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_DATA_ADDRn_OFF(1, 1); |
| 745 | *PP32_BRK_DATA_ADDR_MASK(pp32, 1) = PP32_BRK_CONTEXT_MASK_EN; |
| 746 | *PP32_BRK_DATA_ADDR(pp32, 1) = 0; |
| 747 | } |
| 748 | else |
| 749 | { |
| 750 | addr = get_number(&p, &rlen, 1); |
| 751 | *PP32_BRK_DATA_ADDR(pp32, 1) = addr; |
| 752 | *PP32_BRK_DATA_ADDR_MASK(pp32, 1) = PP32_BRK_CONTEXT_MASK_EN | PP32_BRK_CONTEXT_MASK(0) | PP32_BRK_CONTEXT_MASK(1) | PP32_BRK_CONTEXT_MASK(2) | PP32_BRK_CONTEXT_MASK(3); |
| 753 | *PP32_BRK_TRIG(pp32) = PP32_BRK_GRPi_DATA_ADDRn_ON(1, 1); |
| 754 | } |
| 755 | } |
| 756 | else |
| 757 | { |
| 758 | |
| 759 | printk("echo \"<command>\" > /proc/driver/ifx_ptm/pp32\n"); |
| 760 | printk(" command:\n"); |
| 761 | printk(" unfreeze - unfreeze pp32\n"); |
| 762 | printk(" freeze - freeze pp32\n"); |
| 763 | printk(" start - run pp32\n"); |
| 764 | printk(" stop - stop pp32\n"); |
| 765 | printk(" step - run pp32 with one step only\n"); |
| 766 | printk(" pc0 - pc0 <addr>/off, set break point PC0\n"); |
| 767 | printk(" pc1 - pc1 <addr>/off, set break point PC1\n"); |
| 768 | printk(" daddr0 - daddr0 <addr>/off, set break point data address 0\n"); |
| 769 | printk(" daddr1 - daddr1 <addr>/off, set break point data address 1\n"); |
| 770 | printk(" help - print this screen\n"); |
| 771 | } |
| 772 | |
| 773 | if ( *PP32_BRK_TRIG(pp32) ) |
| 774 | *PP32_CTRL_OPT(pp32) = PP32_CTRL_OPT_STOP_ON_BREAKPOINT_ON; |
| 775 | else |
| 776 | *PP32_CTRL_OPT(pp32) = PP32_CTRL_OPT_STOP_ON_BREAKPOINT_OFF; |
| 777 | |
| 778 | return count; |
| 779 | } |
| 780 | |
| 781 | #endif |
| 782 | |
| 783 | static int stricmp(const char *p1, const char *p2) |
| 784 | { |
| 785 | int c1, c2; |
| 786 | |
| 787 | while ( *p1 && *p2 ) |
| 788 | { |
| 789 | c1 = *p1 >= 'A' && *p1 <= 'Z' ? *p1 + 'a' - 'A' : *p1; |
| 790 | c2 = *p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2; |
| 791 | if ( (c1 -= c2) ) |
| 792 | return c1; |
| 793 | p1++; |
| 794 | p2++; |
| 795 | } |
| 796 | |
| 797 | return *p1 - *p2; |
| 798 | } |
| 799 | |
| 800 | static int strincmp(const char *p1, const char *p2, int n) |
| 801 | { |
| 802 | int c1 = 0, c2; |
| 803 | |
| 804 | while ( n && *p1 && *p2 ) |
| 805 | { |
| 806 | c1 = *p1 >= 'A' && *p1 <= 'Z' ? *p1 + 'a' - 'A' : *p1; |
| 807 | c2 = *p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2; |
| 808 | if ( (c1 -= c2) ) |
| 809 | return c1; |
| 810 | p1++; |
| 811 | p2++; |
| 812 | n--; |
| 813 | } |
| 814 | |
| 815 | return n ? *p1 - *p2 : c1; |
| 816 | } |
| 817 | |
| 818 | static int get_token(char **p1, char **p2, int *len, int *colon) |
| 819 | { |
| 820 | int tlen = 0; |
| 821 | |
| 822 | while ( *len && !((**p1 >= 'A' && **p1 <= 'Z') || (**p1 >= 'a' && **p1<= 'z')) ) |
| 823 | { |
| 824 | (*p1)++; |
| 825 | (*len)--; |
| 826 | } |
| 827 | if ( !*len ) |
| 828 | return 0; |
| 829 | |
| 830 | if ( *colon ) |
| 831 | { |
| 832 | *colon = 0; |
| 833 | *p2 = *p1; |
| 834 | while ( *len && **p2 > ' ' && **p2 != ',' ) |
| 835 | { |
| 836 | if ( **p2 == ':' ) |
| 837 | { |
| 838 | *colon = 1; |
| 839 | break; |
| 840 | } |
| 841 | (*p2)++; |
| 842 | (*len)--; |
| 843 | tlen++; |
| 844 | } |
| 845 | **p2 = 0; |
| 846 | } |
| 847 | else |
| 848 | { |
| 849 | *p2 = *p1; |
| 850 | while ( *len && **p2 > ' ' && **p2 != ',' ) |
| 851 | { |
| 852 | (*p2)++; |
| 853 | (*len)--; |
| 854 | tlen++; |
| 855 | } |
| 856 | **p2 = 0; |
| 857 | } |
| 858 | |
| 859 | return tlen; |
| 860 | } |
| 861 | |
| 862 | static int get_number(char **p, int *len, int is_hex) |
| 863 | { |
| 864 | int ret = 0; |
| 865 | int n = 0; |
| 866 | |
| 867 | if ( (*p)[0] == '0' && (*p)[1] == 'x' ) |
| 868 | { |
| 869 | is_hex = 1; |
| 870 | (*p) += 2; |
| 871 | (*len) -= 2; |
| 872 | } |
| 873 | |
| 874 | if ( is_hex ) |
| 875 | { |
| 876 | while ( *len && ((**p >= '0' && **p <= '9') || (**p >= 'a' && **p <= 'f') || (**p >= 'A' && **p <= 'F')) ) |
| 877 | { |
| 878 | if ( **p >= '0' && **p <= '9' ) |
| 879 | n = **p - '0'; |
| 880 | else if ( **p >= 'a' && **p <= 'f' ) |
| 881 | n = **p - 'a' + 10; |
| 882 | else if ( **p >= 'A' && **p <= 'F' ) |
| 883 | n = **p - 'A' + 10; |
| 884 | ret = (ret << 4) | n; |
| 885 | (*p)++; |
| 886 | (*len)--; |
| 887 | } |
| 888 | } |
| 889 | else |
| 890 | { |
| 891 | while ( *len && **p >= '0' && **p <= '9' ) |
| 892 | { |
| 893 | n = **p - '0'; |
| 894 | ret = ret * 10 + n; |
| 895 | (*p)++; |
| 896 | (*len)--; |
| 897 | } |
| 898 | } |
| 899 | |
| 900 | return ret; |
| 901 | } |
| 902 | |
| 903 | static inline void ignore_space(char **p, int *len) |
| 904 | { |
| 905 | while ( *len && (**p <= ' ' || **p == ':' || **p == '.' || **p == ',') ) |
| 906 | { |
| 907 | (*p)++; |
| 908 | (*len)--; |
| 909 | } |
| 910 | } |
| 911 | |
| 912 | |
| 913 | |
| 914 | /* |
| 915 | * #################################### |
| 916 | * Global Function |
| 917 | * #################################### |
| 918 | */ |
| 919 | |
| 920 | |
| 921 | |
| 922 | /* |
| 923 | * #################################### |
| 924 | * Init/Cleanup API |
| 925 | * #################################### |
| 926 | */ |
| 927 | |
| 928 | static int __init ifx_ptm_test_init(void) |
| 929 | { |
| 930 | proc_file_create(); |
| 931 | |
| 932 | return 0; |
| 933 | } |
| 934 | |
| 935 | static void __exit ifx_ptm_test_exit(void) |
| 936 | { |
| 937 | proc_file_delete(); |
| 938 | } |
| 939 | |
| 940 | module_init(ifx_ptm_test_init); |
| 941 | module_exit(ifx_ptm_test_exit); |
| 942 | |
| 943 | #endif |