systracker_interface.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/device.h>
  4. #include <linux/platform_device.h>
  5. #include <linux/kallsyms.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/delay.h>
  8. #include <linux/sched.h>
  9. #include <linux/of_address.h>
  10. #include <linux/of_irq.h>
  11. #include <asm/memory.h>
  12. #include <asm/system_misc.h>
  13. #include <asm/signal.h>
  14. #include <linux/cpu.h>
  15. #include <mtk_ram_console.h>
  16. #include <mt-plat/sync_write.h>
  17. #include <mt-plat/mt_io.h>
  18. #include "systracker.h"
  19. #define TRACKER_DEBUG 1
  20. void __iomem *BUS_DBG_BASE;
  21. int systracker_irq;
  22. struct systracker_config_t track_config;
  23. struct systracker_entry_t track_entry;
  24. unsigned int is_systracker_irq_registered = 0;
  25. static const struct of_device_id systracker_of_ids[] = {
  26. {.compatible = "mediatek,bus_dbg-v1",},
  27. {}
  28. };
  29. static struct mt_systracker_driver mt_systracker_drv = {
  30. .driver = {
  31. .driver = {
  32. .name = "systracker",
  33. .bus = &platform_bus_type,
  34. .owner = THIS_MODULE,
  35. .of_match_table = systracker_of_ids,
  36. },
  37. .probe = systracker_probe,
  38. .remove = systracker_remove,
  39. .suspend = systracker_suspend,
  40. .resume = systracker_resume,
  41. },
  42. .device = {
  43. .name = "systracker",
  44. .id = 0,
  45. .dev = {
  46. },
  47. },
  48. .reset_systracker = NULL,
  49. .enable_watchpoint = NULL,
  50. .disable_watchpoint = NULL,
  51. .set_watchpoint_address = NULL,
  52. .enable_systracker = NULL,
  53. .disable_systracker = NULL,
  54. .test_systracker = NULL,
  55. .systracker_probe = NULL,
  56. .systracker_remove = NULL,
  57. .systracker_suspend = NULL,
  58. .systracker_resume = NULL,
  59. };
  60. static int systracker_platform_probe_default(struct platform_device *pdev)
  61. {
  62. pr_notice("systracker probe\n");
  63. /* iomap register */
  64. BUS_DBG_BASE = of_iomap(pdev->dev.of_node, 0);
  65. if (!BUS_DBG_BASE) {
  66. pr_err("can't of_iomap for systracker!!\n");
  67. return -ENOMEM;
  68. }
  69. pr_err("of_iomap for systracker @ 0x%p\n", BUS_DBG_BASE);
  70. /* get irq # */
  71. systracker_irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
  72. pr_notice("%s:%d: irq # %d\n", __func__, __LINE__, systracker_irq);
  73. #ifdef SYSTRACKER_TEST_SUIT
  74. if (!is_systracker_irq_registered) {
  75. if (request_irq
  76. (systracker_irq, (irq_handler_t) systracker_isr, IRQF_TRIGGER_LOW, "SYSTRACKER",
  77. NULL)) {
  78. pr_err("SYSTRACKER IRQ LINE NOT AVAILABLE!!\n");
  79. return -1;
  80. }
  81. is_systracker_irq_registered = 1;
  82. }
  83. #endif
  84. /* save entry info */
  85. save_entry();
  86. memset(&track_config, 0, sizeof(struct systracker_config_t));
  87. /* To latch last PC when tracker timeout, we need to enable interrupt mode */
  88. track_config.enable_timeout = 1;
  89. track_config.enable_slave_err = 1;
  90. track_config.enable_irq = 1;
  91. track_config.timeout_ms = 100;
  92. systracker_reset();
  93. systracker_enable();
  94. return 0;
  95. }
  96. int systracker_probe(struct platform_device *pdev)
  97. {
  98. if (mt_systracker_drv.systracker_probe)
  99. return mt_systracker_drv.systracker_probe(pdev);
  100. else
  101. return systracker_platform_probe_default(pdev);
  102. }
  103. int systracker_remove(struct platform_device *pdev)
  104. {
  105. if (mt_systracker_drv.systracker_remove)
  106. return mt_systracker_drv.systracker_remove(pdev);
  107. return 0;
  108. }
  109. int systracker_suspend(struct platform_device *pdev, pm_message_t state)
  110. {
  111. if (mt_systracker_drv.systracker_suspend)
  112. return mt_systracker_drv.systracker_suspend(pdev, state);
  113. return 0;
  114. }
  115. static int systracker_resume_default(struct platform_device *pdev)
  116. {
  117. if (track_config.state || track_config.enable_wp)
  118. systracker_enable();
  119. return 0;
  120. }
  121. int systracker_resume(struct platform_device *pdev)
  122. {
  123. if (mt_systracker_drv.systracker_resume)
  124. return mt_systracker_drv.systracker_resume(pdev);
  125. else
  126. return systracker_resume_default(pdev);
  127. }
  128. /* Some chip do not have reg dump, define a weak to avoid build error */
  129. extern int mt_reg_dump(char *buf) __attribute__ ((weak));
  130. /*
  131. * save entry info early
  132. */
  133. void save_entry(void)
  134. {
  135. int i = 0;
  136. track_entry.dbg_con = readl(IOMEM(BUS_DBG_CON));
  137. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  138. track_entry.ar_track_l[i] = readl(IOMEM(BUS_DBG_AR_TRACK_L(i)));
  139. track_entry.ar_track_h[i] = readl(IOMEM(BUS_DBG_AR_TRACK_H(i)));
  140. track_entry.ar_trans_tid[i] = readl(IOMEM(BUS_DBG_AR_TRANS_TID(i)));
  141. track_entry.aw_track_l[i] = readl(IOMEM(BUS_DBG_AW_TRACK_L(i)));
  142. track_entry.aw_track_h[i] = readl(IOMEM(BUS_DBG_AW_TRACK_H(i)));
  143. track_entry.aw_trans_tid[i] = readl(IOMEM(BUS_DBG_AW_TRANS_TID(i)));
  144. }
  145. }
  146. #ifdef SYSTRACKER_TEST_SUIT
  147. void systracker_test_cleanup(void)
  148. {
  149. if (mt_systracker_drv.systracker_test_cleanup)
  150. return mt_systracker_drv.systracker_test_cleanup();
  151. }
  152. #endif
  153. static void tracker_print(void)
  154. {
  155. unsigned int reg_value;
  156. int i;
  157. unsigned int entry_valid;
  158. unsigned int entry_tid;
  159. unsigned int entry_id;
  160. unsigned int entry_address;
  161. unsigned int entry_data_size;
  162. unsigned int entry_burst_length;
  163. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  164. entry_address = track_entry.ar_track_l[i];
  165. reg_value = track_entry.ar_track_h[i];
  166. entry_valid = extract_n2mbits(reg_value, 19, 19);
  167. entry_id = extract_n2mbits(reg_value, 7, 18);
  168. entry_data_size = extract_n2mbits(reg_value, 4, 6);
  169. entry_burst_length = extract_n2mbits(reg_value, 0, 3);
  170. entry_tid = track_entry.ar_trans_tid[i];
  171. pr_notice("read entry = %d, valid = 0x%x, tid = 0x%x, read id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  172. i, entry_valid, entry_tid, entry_id,
  173. entry_address, entry_data_size, entry_burst_length);
  174. }
  175. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  176. entry_address = track_entry.aw_track_l[i];
  177. reg_value = track_entry.aw_track_h[i];
  178. entry_valid = extract_n2mbits(reg_value, 19, 19);
  179. entry_id = extract_n2mbits(reg_value, 7, 18);
  180. entry_data_size = extract_n2mbits(reg_value, 4, 6);
  181. entry_burst_length = extract_n2mbits(reg_value, 0, 3);
  182. entry_tid = track_entry.aw_trans_tid[i];
  183. pr_notice("write entry = %d, valid = 0x%x, tid = 0x%x, write id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  184. i, entry_valid, entry_tid, entry_id,
  185. entry_address, entry_data_size, entry_burst_length);
  186. }
  187. }
  188. irqreturn_t systracker_isr(void)
  189. {
  190. unsigned int con;
  191. static char reg_buf[512];
  192. #ifdef SYSTRACKER_TEST_SUIT
  193. systracker_test_cleanup();
  194. #endif
  195. save_entry();
  196. pr_notice("Sys Tracker ISR\n");
  197. pr_notice("in systracker_interface.c\n");
  198. con = readl(IOMEM(BUS_DBG_CON));
  199. writel(con | BUS_DBG_CON_IRQ_CLR, IOMEM(BUS_DBG_CON));
  200. mb();
  201. if (con & BUS_DBG_CON_IRQ_WP_STA) {
  202. pr_notice("[TRACKER] Watch address: 0x%x was touched\n", track_config.wp_phy_address);
  203. if (mt_reg_dump) {
  204. if (mt_reg_dump(reg_buf) == 0)
  205. pr_notice("%s\n", reg_buf);
  206. }
  207. }
  208. if (con & BUS_DBG_CON_IRQ_AR_STA) {
  209. pr_notice("[TRAKER] Read time out trigger\n");
  210. tracker_print();
  211. }
  212. if (con & BUS_DBG_CON_IRQ_AW_STA) {
  213. pr_notice("[TRAKER] Write time out trigger\n");
  214. tracker_print();
  215. }
  216. return IRQ_HANDLED;
  217. }
  218. static int systracker_watchpoint_enable_default(void)
  219. {
  220. if (!is_systracker_irq_registered) {
  221. if (request_irq
  222. (systracker_irq, (irq_handler_t) systracker_isr, IRQF_TRIGGER_LOW, "SYSTRACKER",
  223. NULL)) {
  224. pr_err("SYSTRACKER IRQ LINE NOT AVAILABLE!!\n");
  225. return -1;
  226. }
  227. is_systracker_irq_registered = 1;
  228. }
  229. track_config.enable_wp = 1;
  230. writel(track_config.wp_phy_address, IOMEM(BUS_DBG_WP));
  231. writel(0x0000000F, IOMEM(BUS_DBG_WP_MASK));
  232. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_WP_EN, IOMEM(BUS_DBG_CON));
  233. pr_notice("track_config.wp_phy_address = 0x%x\n", track_config.wp_phy_address);
  234. mb();
  235. return 0;
  236. }
  237. int systracker_watchpoint_enable(void)
  238. {
  239. if (mt_systracker_drv.enable_watchpoint)
  240. return mt_systracker_drv.enable_watchpoint();
  241. else
  242. return systracker_watchpoint_enable_default();
  243. }
  244. static int systracker_watchpoint_disable_default(void)
  245. {
  246. track_config.enable_wp = 0;
  247. writel(readl(IOMEM(BUS_DBG_CON)) & ~BUS_DBG_CON_WP_EN, IOMEM(BUS_DBG_CON));
  248. mb();
  249. return 0;
  250. }
  251. int systracker_watchpoint_disable(void)
  252. {
  253. if (mt_systracker_drv.disable_watchpoint)
  254. return mt_systracker_drv.disable_watchpoint();
  255. else
  256. return systracker_watchpoint_disable_default();
  257. }
  258. static void systracker_reset_default(void)
  259. {
  260. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_SW_RST, IOMEM(BUS_DBG_CON));
  261. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_IRQ_CLR, IOMEM(BUS_DBG_CON));
  262. mb();
  263. }
  264. void systracker_reset(void)
  265. {
  266. if (mt_systracker_drv.reset_systracker)
  267. mt_systracker_drv.reset_systracker();
  268. else
  269. systracker_reset_default();
  270. }
  271. static unsigned int systracker_timeout_value_default(void)
  272. {
  273. /* prescale = (133 * (10 ^ 6)) / 16 = 8312500/s */
  274. return (BUS_DBG_BUS_MHZ * 1000 / 16) * track_config.timeout_ms;
  275. }
  276. static unsigned int systracker_timeout_value(void)
  277. {
  278. if (mt_systracker_drv.systracker_timeout_value)
  279. return mt_systracker_drv.systracker_timeout_value();
  280. else
  281. return systracker_timeout_value_default();
  282. }
  283. static void systracker_enable_default(void)
  284. {
  285. unsigned int con;
  286. unsigned int timer_control_value;
  287. timer_control_value = systracker_timeout_value();
  288. writel(timer_control_value, IOMEM(BUS_DBG_TIMER_CON));
  289. track_config.state = 1;
  290. con = BUS_DBG_CON_BUS_DBG_EN | BUS_DBG_CON_BUS_OT_EN;
  291. if (track_config.enable_timeout)
  292. con |= BUS_DBG_CON_TIMEOUT_EN;
  293. if (track_config.enable_slave_err)
  294. con |= BUS_DBG_CON_SLV_ERR_EN;
  295. if (track_config.enable_irq)
  296. con |= BUS_DBG_CON_IRQ_EN;
  297. /* for safety, BUS_DBG_CON_IRQ_WP_EN is set later...
  298. K2 encouter many strange behaviors when set BUS_DBG_CON_IRQ_WP_EN at the same time */
  299. con &= ~BUS_DBG_CON_IRQ_WP_EN;
  300. con |= BUS_DBG_CON_HALT_ON_EN;
  301. writel(con, IOMEM(BUS_DBG_CON));
  302. mb();
  303. con |= BUS_DBG_CON_IRQ_WP_EN;
  304. writel(con, IOMEM(BUS_DBG_CON));
  305. mb();
  306. }
  307. void systracker_enable(void)
  308. {
  309. if (mt_systracker_drv.enable_systracker)
  310. mt_systracker_drv.enable_systracker();
  311. else
  312. systracker_enable_default();
  313. }
  314. void enable_systracker(void)
  315. {
  316. systracker_enable();
  317. }
  318. static void systracker_disable_default(void)
  319. {
  320. track_config.state = 0;
  321. writel(readl(IOMEM(BUS_DBG_CON)) & ~BUS_DBG_CON_BUS_DBG_EN, IOMEM(BUS_DBG_CON));
  322. mb();
  323. }
  324. void systracker_disable(void)
  325. {
  326. if (mt_systracker_drv.disable_systracker)
  327. mt_systracker_drv.disable_systracker();
  328. else
  329. systracker_disable_default();
  330. }
  331. int systracker_hook_fault(void)
  332. {
  333. if (mt_systracker_drv.systracker_hook_fault)
  334. return mt_systracker_drv.systracker_hook_fault();
  335. pr_warn("mt_systracker_drv.systracker_hook_fault is NULL");
  336. return -1;
  337. }
  338. int systracker_test_init(void)
  339. {
  340. if (mt_systracker_drv.systracker_test_init)
  341. return mt_systracker_drv.systracker_test_init();
  342. pr_warn("mt_systracker_drv.systracker_test_init is NULL");
  343. return -1;
  344. }
  345. struct mt_systracker_driver *get_mt_systracker_drv(void)
  346. {
  347. return &mt_systracker_drv;
  348. }
  349. int tracker_dump(char *buf)
  350. {
  351. char *ptr = buf;
  352. unsigned int reg_value;
  353. int i;
  354. unsigned int entry_valid;
  355. unsigned int entry_tid;
  356. unsigned int entry_id;
  357. unsigned int entry_address;
  358. unsigned int entry_data_size;
  359. unsigned int entry_burst_length;
  360. /*
  361. if(is_systracker_device_registered)
  362. */
  363. {
  364. /* Get tracker info and save to buf */
  365. /* BUS_DBG_AR_TRACK_L(__n)
  366. * [31:0] ARADDR: DBG read tracker entry read address
  367. */
  368. /* BUS_DBG_AR_TRACK_H(__n)
  369. * [14] Valid:DBG read tracker entry valid
  370. * [13:7] ARID:DBG read tracker entry read ID
  371. * [6:4] ARSIZE:DBG read tracker entry read data size
  372. * [3:0] ARLEN: DBG read tracker entry read burst length
  373. */
  374. /* BUS_DBG_AR_TRACK_TID(__n)
  375. * [2:0] BUS_DBG_AR_TRANS0_ENTRY_ID: DBG read tracker entry ID of 1st transaction
  376. */
  377. #ifdef TRACKER_DEBUG
  378. pr_debug("Sys Tracker Dump\n");
  379. #endif
  380. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  381. entry_address = track_entry.ar_track_l[i];
  382. reg_value = track_entry.ar_track_h[i];
  383. entry_valid = extract_n2mbits(reg_value, 19, 19);
  384. entry_id = extract_n2mbits(reg_value, 7, 18);
  385. entry_data_size = extract_n2mbits(reg_value, 4, 6);
  386. entry_burst_length = extract_n2mbits(reg_value, 0, 3);
  387. entry_tid = track_entry.ar_trans_tid[i];
  388. ptr += sprintf(ptr,
  389. "read entry = %d, valid = 0x%x, tid = 0x%x, read id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  390. i, entry_valid, entry_tid, entry_id,
  391. entry_address, entry_data_size, entry_burst_length);
  392. #ifdef TRACKER_DEBUG
  393. pr_debug("read entry = %d, valid = 0x%x, tid = 0x%x, read id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  394. i, entry_valid, entry_tid, entry_id,
  395. entry_address, entry_data_size, entry_burst_length);
  396. #endif
  397. }
  398. /* BUS_DBG_AW_TRACK_L(__n)
  399. * [31:0] AWADDR: DBG write tracker entry write address
  400. */
  401. /* BUS_DBG_AW_TRACK_H(__n)
  402. * [14] Valid:DBG write tracker entry valid
  403. * [13:7] ARID:DBG write tracker entry write ID
  404. * [6:4] ARSIZE:DBG write tracker entry write data size
  405. * [3:0] ARLEN: DBG write tracker entry write burst length
  406. */
  407. /* BUS_DBG_AW_TRACK_TID(__n)
  408. * [2:0] BUS_DBG_AW_TRANS0_ENTRY_ID: DBG write tracker entry ID of 1st transaction
  409. */
  410. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  411. entry_address = track_entry.aw_track_l[i];
  412. reg_value = track_entry.aw_track_h[i];
  413. entry_valid = extract_n2mbits(reg_value, 19, 19);
  414. entry_id = extract_n2mbits(reg_value, 7, 18);
  415. entry_data_size = extract_n2mbits(reg_value, 4, 6);
  416. entry_burst_length = extract_n2mbits(reg_value, 0, 3);
  417. entry_tid = track_entry.aw_trans_tid[i];
  418. ptr += sprintf(ptr,
  419. "write entry = %d, valid = 0x%x, tid = 0x%x, write id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  420. i, entry_valid, entry_tid, entry_id, entry_address,
  421. entry_data_size, entry_burst_length);
  422. #ifdef TRACKER_DEBUG
  423. pr_debug("write entry = %d, valid = 0x%x, tid = 0x%x, write id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  424. i, entry_valid, entry_tid, entry_id, entry_address,
  425. entry_data_size, entry_burst_length);
  426. #endif
  427. }
  428. return strlen(buf);
  429. }
  430. return -1;
  431. }
  432. static ssize_t tracker_run_show(struct device_driver *driver, char *buf)
  433. {
  434. return snprintf(buf, PAGE_SIZE, "%x\n", readl(IOMEM(BUS_DBG_CON)));
  435. }
  436. static ssize_t tracker_run_store(struct device_driver *driver, const char *buf, size_t count)
  437. {
  438. unsigned int value;
  439. if (unlikely(kstrtou32(buf, 10, &value) != 1))
  440. return -EINVAL;
  441. if (value == 1)
  442. systracker_enable();
  443. else if (value == 0)
  444. systracker_disable();
  445. else
  446. return -EINVAL;
  447. return count;
  448. }
  449. DRIVER_ATTR(tracker_run, 0644, tracker_run_show, tracker_run_store);
  450. static ssize_t enable_wp_show(struct device_driver *driver, char *buf)
  451. {
  452. return snprintf(buf, PAGE_SIZE, "%x\n", track_config.enable_wp);
  453. }
  454. static ssize_t enable_wp_store(struct device_driver *driver, const char *buf, size_t count)
  455. {
  456. unsigned int value;
  457. if (unlikely(kstrtou32(buf, 10, &value) != 1))
  458. return -EINVAL;
  459. if (value == 1)
  460. systracker_watchpoint_enable();
  461. else if (value == 0)
  462. systracker_watchpoint_disable();
  463. else
  464. return -EINVAL;
  465. return count;
  466. }
  467. DRIVER_ATTR(enable_wp, 0644, enable_wp_show, enable_wp_store);
  468. static ssize_t set_wp_address_show(struct device_driver *driver, char *buf)
  469. {
  470. return snprintf(buf, PAGE_SIZE, "%x\n", track_config.wp_phy_address);
  471. }
  472. int systracker_set_watchpoint_addr(unsigned int addr)
  473. {
  474. if (mt_systracker_drv.set_watchpoint_address)
  475. return mt_systracker_drv.set_watchpoint_address(addr);
  476. track_config.wp_phy_address = addr;
  477. return 0;
  478. }
  479. static ssize_t set_wp_address_store(struct device_driver *driver, const char *buf, size_t count)
  480. {
  481. unsigned int value;
  482. if (unlikely(kstrtou32(buf, 10, &value) != 1))
  483. return -EINVAL;
  484. pr_notice("watch address:0x%x\n", value);
  485. systracker_set_watchpoint_addr(value);
  486. return count;
  487. }
  488. DRIVER_ATTR(set_wp_address, 0644, set_wp_address_show, set_wp_address_store);
  489. static ssize_t tracker_entry_dump_show(struct device_driver *driver, char *buf)
  490. {
  491. int ret = tracker_dump(buf);
  492. if (ret == -1)
  493. pr_crit("Dump error in %s, %d\n", __func__, __LINE__);
  494. /* FOR test
  495. test_systracker();
  496. */
  497. return strlen(buf);
  498. }
  499. static ssize_t tracker_swtrst_show(struct device_driver *driver, char *buf)
  500. {
  501. return 0;
  502. }
  503. static ssize_t tracker_swtrst_store(struct device_driver *driver, const char *buf, size_t count)
  504. {
  505. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_SW_RST, IOMEM(BUS_DBG_CON));
  506. return count;
  507. }
  508. DRIVER_ATTR(tracker_swtrst, 0664, tracker_swtrst_show, tracker_swtrst_store);
  509. #ifdef SYSTRACKER_TEST_SUIT
  510. void systracker_wp_test(void)
  511. {
  512. if (mt_systracker_drv.systracker_wp_test)
  513. mt_systracker_drv.systracker_wp_test();
  514. else
  515. pr_notice("mt_systracker_drv.systracker_wp_test is NULL");
  516. }
  517. /* this function expects */
  518. void systracker_read_timeout_test(void)
  519. {
  520. pr_notice("we are going to have read timeout\n");
  521. if (mt_systracker_drv.systracker_read_timeout_test)
  522. mt_systracker_drv.systracker_read_timeout_test();
  523. else
  524. pr_notice("mt_systracker_drv.systracker_read_timeout_test is NULL");
  525. }
  526. void systracker_write_timeout_test(void)
  527. {
  528. pr_notice("we are going to have write timeout\n");
  529. if (mt_systracker_drv.systracker_write_timeout_test)
  530. mt_systracker_drv.systracker_write_timeout_test();
  531. else
  532. pr_notice("mt_systracker_drv.systracker_write_timeout_test is NULL");
  533. }
  534. void systracker_timeout_withrecord_test(void)
  535. {
  536. pr_notice("we are going to have read timeout, and then wdt happens\n");
  537. pr_notice("Please check if there is related backtrace info in aee\n");
  538. if (mt_systracker_drv.systracker_withrecord_test)
  539. mt_systracker_drv.systracker_withrecord_test();
  540. else
  541. pr_notice("mt_systracker_drv.systracker_withrecord_test is NULL");
  542. }
  543. void systracker_notimeout_test(void)
  544. {
  545. pr_notice("should hang forever from now on, never come back...\n");
  546. pr_notice("ICE should not connect anymore\n");
  547. if (mt_systracker_drv.systracker_notimeout_test)
  548. mt_systracker_drv.systracker_notimeout_test();
  549. else
  550. pr_notice("mt_systracker_drv.systracker_notimeout_test is NULL");
  551. }
  552. static ssize_t test_suit_show(struct device_driver *driver, char *buf)
  553. {
  554. return snprintf(buf, PAGE_SIZE, "==Systracker test==\n"
  555. "1.Systracker show dump test\n"
  556. "2.Systracker watchpoint test\n"
  557. "3.Systracker read timeout test\n"
  558. "4.Systracker write timeout test\n"
  559. "5.Systracker timeout with record test\n" "6.Systracker no timeout test\n");
  560. }
  561. static ssize_t test_suit_store(struct device_driver *driver, const char *buf, size_t count)
  562. {
  563. char *p = (char *)buf;
  564. unsigned long int num;
  565. ssize_t ret;
  566. ret = kstrtoul(p, 10, &num);
  567. if (ret == 0) {
  568. switch (num) {
  569. /* Test Systracker Function */
  570. case 1:
  571. return tracker_entry_dump_show(driver, p);
  572. case 2:
  573. systracker_wp_test();
  574. break;
  575. case 3:
  576. systracker_read_timeout_test();
  577. break;
  578. case 4:
  579. systracker_write_timeout_test();
  580. break;
  581. case 5:
  582. systracker_timeout_withrecord_test();
  583. break;
  584. case 6:
  585. systracker_notimeout_test();
  586. break;
  587. default:
  588. break;
  589. }
  590. }
  591. return count;
  592. }
  593. DRIVER_ATTR(test_suit, 0664, test_suit_show, test_suit_store);
  594. #endif
  595. static ssize_t tracker_entry_dump_store(struct device_driver *driver, const char *buf, size_t count)
  596. {
  597. return count;
  598. }
  599. DRIVER_ATTR(tracker_entry_dump, 0664, tracker_entry_dump_show, tracker_entry_dump_store);
  600. static ssize_t tracker_last_status_show(struct device_driver *driver, char *buf)
  601. {
  602. if (track_entry.dbg_con & (BUS_DBG_CON_IRQ_AR_STA | BUS_DBG_CON_IRQ_AW_STA))
  603. return snprintf(buf, PAGE_SIZE, "1\n");
  604. else
  605. return snprintf(buf, PAGE_SIZE, "0\n");
  606. }
  607. static ssize_t tracker_last_status_store(struct device_driver *driver, const char *buf,
  608. size_t count)
  609. {
  610. return count;
  611. }
  612. DRIVER_ATTR(tracker_last_status, 0664, tracker_last_status_show, tracker_last_status_store);
  613. /*
  614. * driver initialization entry point
  615. */
  616. static int __init systracker_init(void)
  617. {
  618. int err;
  619. int ret = 0;
  620. #ifdef SYSTRACKER_TEST_SUIT
  621. systracker_test_init();
  622. #endif
  623. err = platform_driver_register(&mt_systracker_drv.driver);
  624. if (err)
  625. return err;
  626. /* Create sysfs entry */
  627. ret = driver_create_file(&mt_systracker_drv.driver.driver, &driver_attr_tracker_entry_dump);
  628. ret |= driver_create_file(&mt_systracker_drv.driver.driver, &driver_attr_tracker_run);
  629. ret |= driver_create_file(&mt_systracker_drv.driver.driver, &driver_attr_enable_wp);
  630. ret |= driver_create_file(&mt_systracker_drv.driver.driver, &driver_attr_set_wp_address);
  631. ret |= driver_create_file(&mt_systracker_drv.driver.driver, &driver_attr_tracker_swtrst);
  632. ret |=
  633. driver_create_file(&mt_systracker_drv.driver.driver, &driver_attr_tracker_last_status);
  634. #ifdef SYSTRACKER_TEST_SUIT
  635. ret |= driver_create_file(&mt_systracker_drv.driver.driver, &driver_attr_test_suit);
  636. #endif
  637. if (ret)
  638. pr_err("Fail to create systracker_drv sysfs files");
  639. systracker_hook_fault();
  640. pr_alert("systracker init done\n");
  641. return 0;
  642. }
  643. /*
  644. * driver exit point
  645. */
  646. static void __exit systracker_exit(void)
  647. {
  648. }
  649. module_init(systracker_init);
  650. module_exit(systracker_exit);