printk_dma.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*
  2. * Copyright (c) 2018 Nordic Semiconductor ASA
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. */
  7. #include <kernel.h>
  8. #include <device.h>
  9. #include <init.h>
  10. #include <string.h>
  11. #include <drivers/uart.h>
  12. #include <drivers/uart_dma.h>
  13. #include "cbuf.h"
  14. #include <debug/actions_exception.h>
  15. #include <soc.h>
  16. #define TRUE 1
  17. #define FALSE 0
  18. typedef struct
  19. {
  20. struct device *uart_dev;
  21. cbuf_t cbuf;
  22. //uint8_t sending;
  23. uint8_t init;
  24. uint8_t panic;
  25. #ifdef CONFIG_PRINTK_DMA_FULL_LOST
  26. uint32_t drop_bytes;
  27. #endif
  28. cbuf_dma_t dma_setting;
  29. }printk_ctx_t;
  30. static printk_ctx_t g_pr_ctx;
  31. #ifdef CONFIG_SOC_NO_PSRAM
  32. __in_section_unique(trace.printk_buffer.noinit)
  33. #endif
  34. static unsigned char dma_printk_buffer[CONFIG_DMA_PRINTK_BUF_SIZE];
  35. K_SEM_DEFINE(log_uart_dma_sem, 0, 1);
  36. static void dma_stop_tx(printk_ctx_t *ctx)
  37. {
  38. unsigned int lock;
  39. lock = irq_lock();
  40. if (ctx->dma_setting.read_len != 0)
  41. {
  42. if(cbuf_is_ptr_valid(&ctx->cbuf, (uint32_t)ctx->dma_setting.start_addr)){
  43. cbuf_dma_update_read_ptr(&ctx->cbuf, ctx->dma_setting.read_len);
  44. }
  45. ctx->dma_setting.read_len = 0;
  46. }
  47. //ctx->sending = FALSE;
  48. uart_acts_dma_send_stop(ctx->uart_dev);
  49. irq_unlock(lock);
  50. }
  51. static int _dma_start_tx(printk_ctx_t *ctx)
  52. {
  53. int32_t data_size;
  54. //if(!ctx->sending){
  55. if (ctx->dma_setting.read_len == 0){
  56. data_size = cbuf_get_used_space(&ctx->cbuf);
  57. if(data_size > 0){
  58. if(data_size > (CONFIG_DMA_PRINTK_BUF_SIZE/4)) // Prevents printk threads from blocking for too long
  59. data_size = (CONFIG_DMA_PRINTK_BUF_SIZE/4);
  60. cbuf_dma_read(&ctx->cbuf, &ctx->dma_setting, (uint32_t)data_size);
  61. if(ctx->dma_setting.read_len){
  62. ///ctx->sending = TRUE;
  63. uart_dma_send(ctx->uart_dev, (char *)ctx->dma_setting.start_addr, ctx->dma_setting.read_len);
  64. return 1;
  65. }
  66. }
  67. return 0;
  68. }
  69. return 1;
  70. }
  71. static int dma_start_tx(printk_ctx_t *ctx)
  72. {
  73. int ret;
  74. unsigned int lock;
  75. lock = irq_lock();
  76. ret = _dma_start_tx(ctx);
  77. irq_unlock(lock);
  78. return ret;
  79. }
  80. #ifdef CONFIG_PRINTK_DMA_FULL_LOST
  81. static void check_drops_output(printk_ctx_t *p_ctx)
  82. {
  83. uint32_t irq_flag;
  84. int free_space;
  85. char tmp_buf[8];
  86. if(p_ctx->drop_bytes == 0)
  87. return;
  88. irq_flag = irq_lock();
  89. free_space = cbuf_get_free_space(&p_ctx->cbuf);
  90. if(free_space > 8){
  91. tmp_buf[0] = '\n';
  92. tmp_buf[1] = '@';
  93. p_ctx->drop_bytes = p_ctx->drop_bytes % 10000;
  94. tmp_buf[2] = '0' + p_ctx->drop_bytes/1000;
  95. p_ctx->drop_bytes = p_ctx->drop_bytes % 1000;
  96. tmp_buf[3] = '0' + p_ctx->drop_bytes/100;
  97. p_ctx->drop_bytes = p_ctx->drop_bytes % 100;
  98. tmp_buf[4] = '0' + p_ctx->drop_bytes/10;
  99. p_ctx->drop_bytes = p_ctx->drop_bytes % 10;
  100. tmp_buf[5] = '0' + p_ctx->drop_bytes;
  101. tmp_buf[6] = '@';
  102. tmp_buf[7] = '\n';
  103. cbuf_write(&p_ctx->cbuf, (void *)tmp_buf, 8);
  104. }
  105. p_ctx->drop_bytes = 0;
  106. irq_unlock(irq_flag);
  107. }
  108. #endif
  109. static void dma_send_finshed(printk_ctx_t *ctx)
  110. {
  111. dma_stop_tx(ctx);
  112. dma_start_tx(ctx);
  113. #ifdef CONFIG_PRINTK_DMA_FULL_LOST
  114. check_drops_output(ctx);
  115. #endif
  116. k_sem_give(&log_uart_dma_sem);
  117. }
  118. static void dma_send_sync(printk_ctx_t *ctx)
  119. {
  120. unsigned int lock;
  121. // lock irq avoid print nested call in isr context, maybe cause lock irq too long.
  122. lock = irq_lock();
  123. // output all cache data
  124. while(1){
  125. // wait transmit finished
  126. if(uart_acts_dma_send_complete(ctx->uart_dev)){
  127. dma_stop_tx(ctx);
  128. #ifdef CONFIG_PRINTK_DMA_FULL_LOST
  129. check_drops_output(ctx);
  130. #endif
  131. }else{
  132. continue;
  133. }
  134. if(!dma_start_tx(ctx)){
  135. break;
  136. }
  137. }
  138. irq_unlock(lock);
  139. }
  140. static void uart_dma_callback(const struct device *dev, void *arg, uint32_t ch, int error)
  141. {
  142. printk_ctx_t *ctx = (printk_ctx_t *)arg;
  143. dma_send_finshed(ctx);
  144. }
  145. static int uart_dma_switch(printk_ctx_t *ctx, unsigned int use_dma, dma_callback_t dma_handler)
  146. {
  147. if(use_dma){
  148. if(uart_dma_send_init(ctx->uart_dev, uart_dma_callback, ctx))
  149. return -1;
  150. uart_fifo_switch(ctx->uart_dev, 1, UART_FIFO_TYPE_DMA);
  151. }else{
  152. uart_dma_send_stop(ctx->uart_dev);
  153. uart_fifo_switch(ctx->uart_dev, 1, UART_FIFO_TYPE_CPU);
  154. }
  155. return 0;
  156. }
  157. static int cbuf_output(const unsigned char *buf, unsigned int len, printk_ctx_t *p_ctx)
  158. {
  159. uint32_t irq_flag;
  160. int free_space;
  161. if(len == 0)
  162. return 0;
  163. while(1){
  164. irq_flag = irq_lock();
  165. free_space = cbuf_get_free_space(&p_ctx->cbuf);
  166. if(free_space > len ){
  167. break;
  168. }else{
  169. #ifdef CONFIG_PRINTK_DMA_FULL_LOST
  170. p_ctx->drop_bytes += len;
  171. irq_unlock(irq_flag);
  172. if(p_ctx->drop_bytes > 0x10000 ) {
  173. if(uart_acts_dma_send_complete(p_ctx->uart_dev) && p_ctx->dma_setting.read_len){ // lost irq
  174. dma_send_finshed(p_ctx);
  175. continue;
  176. }
  177. }
  178. return 0;
  179. #else
  180. irq_unlock(irq_flag);
  181. if(k_is_in_isr()) {
  182. while(!uart_acts_dma_send_complete(p_ctx->uart_dev));
  183. dma_send_finshed(p_ctx);
  184. continue;
  185. }
  186. if(k_sem_take(&log_uart_dma_sem, K_MSEC(500))){
  187. #if 1
  188. if(uart_acts_dma_send_complete(p_ctx->uart_dev) && p_ctx->dma_setting.read_len){ // lost irq
  189. dma_send_finshed(p_ctx);
  190. }
  191. #endif
  192. }
  193. #endif
  194. }
  195. }
  196. cbuf_write(&p_ctx->cbuf, (void *)buf, len);
  197. irq_unlock(irq_flag);
  198. return len;
  199. }
  200. /*must > 32*/
  201. #define CTX_TMP_BUF_LEN 64
  202. struct buf_out_ctx {
  203. uint8_t count;
  204. char buf[CTX_TMP_BUF_LEN];
  205. };
  206. static int buf_char_out(int c, void *ctx_p)
  207. {
  208. struct buf_out_ctx *ctx = ctx_p;
  209. if(ctx->count >= (CTX_TMP_BUF_LEN-2)){
  210. cbuf_output(ctx->buf, ctx->count, &g_pr_ctx);
  211. ctx->count = 0;
  212. }
  213. if ('\n' == c) {
  214. ctx->buf[ctx->count++] = '\r';
  215. }
  216. ctx->buf[ctx->count++] = c;
  217. return 0;
  218. }
  219. static void ctx_buf_flush(struct buf_out_ctx *ctx)
  220. {
  221. if(ctx->count){
  222. cbuf_output(ctx->buf, ctx->count, &g_pr_ctx);
  223. ctx->count = 0;
  224. }
  225. }
  226. #ifdef CONFIG_PRINTK_TIME_FREFIX
  227. static const uint8_t digits[] = "0123456789abcdef";
  228. static int hex_to_str_num(char *num_str, int buflen, uint32_t num_val, int mv)
  229. {
  230. uint8_t ch;
  231. int num_len, len, i;
  232. buflen--;
  233. num_len = buflen;
  234. while(num_val != 0){
  235. if(num_len < 0)
  236. break;
  237. ch = digits[num_val % 10];
  238. num_str[num_len--] = ch;
  239. num_val /= 10;
  240. }
  241. len = (buflen-num_len);
  242. num_len++;
  243. if(mv) {
  244. for(i = 0; i < len; i++){
  245. num_str[i] = num_str[num_len++];
  246. }
  247. }else{
  248. for(i = 0; i < num_len; i++){
  249. num_str[i] = '0';
  250. }
  251. len = buflen+1;
  252. }
  253. return len;
  254. }
  255. //#define PRINT_US
  256. #ifdef PRINT_US
  257. static struct k_timer ktimer_printk;
  258. static uint32_t g_low_cycle, g_high_cycle;
  259. static void timer_printk_update(uint32_t *low, uint32_t *high)
  260. {
  261. uint32_t cyc;
  262. unsigned int lock;
  263. lock = irq_lock();
  264. cyc = k_cycle_get_32();
  265. if(cyc < g_low_cycle)
  266. g_high_cycle++;
  267. g_low_cycle = cyc;
  268. if(low != NULL)
  269. *low = g_low_cycle;
  270. if(high != NULL)
  271. *high = g_high_cycle;
  272. irq_unlock(lock);
  273. }
  274. static void timer_printk_cyc(struct k_timer *timer)
  275. {
  276. timer_printk_update(NULL, NULL);
  277. }
  278. static void timer_printk_init(void)
  279. {
  280. g_low_cycle = k_cycle_get_32();
  281. g_high_cycle = 0;
  282. k_timer_init(&ktimer_printk, timer_printk_cyc, NULL);
  283. k_timer_start(&ktimer_printk, K_MSEC(1000), K_MSEC(1000));
  284. }
  285. static void get_time_s_us(uint32_t *s, uint32_t *us)
  286. {
  287. uint32_t hcyc, lcyc;
  288. uint64_t cyc, sec;
  289. timer_printk_update(&lcyc, &hcyc);
  290. cyc = hcyc;
  291. cyc = (cyc << 32) + lcyc;
  292. cyc =cyc/(sys_clock_hw_cycles_per_sec()/1000000); // us
  293. sec = cyc/1000000; //second
  294. *us = cyc - sec*1000000; //us
  295. *s = sec;
  296. }
  297. static int get_time_prefix(char *num_str)
  298. {
  299. uint32_t sec, us;
  300. char *pc = num_str;
  301. get_time_s_us(&sec, &us);
  302. *pc++='[';
  303. if(sec) {
  304. pc += hex_to_str_num(pc, 9, sec, 1);
  305. *pc++=':';
  306. }else{
  307. *pc++='0';
  308. *pc++=':';
  309. }
  310. sec = us/1000;
  311. pc += hex_to_str_num(pc, 3, sec , 0);
  312. *pc++='.';
  313. pc += hex_to_str_num(pc, 3, us-sec*1000 , 0);
  314. *pc++=']';
  315. return (pc-num_str);
  316. }
  317. #else
  318. static int get_time_prefix(char *num_str)
  319. {
  320. int64_t ms_cnt;
  321. uint32_t sec, ms;
  322. char *pc = num_str;
  323. ms_cnt = k_uptime_get();
  324. sec = ms_cnt/1000;
  325. ms = ms_cnt - sec*1000;
  326. *pc++='[';
  327. if(sec) {
  328. pc += hex_to_str_num(pc, 9, sec, 1);
  329. *pc++=':';
  330. }else{
  331. *pc++='0';
  332. *pc++=':';
  333. }
  334. pc += hex_to_str_num(pc, 3, ms , 0);
  335. *pc++=']';
  336. return (pc-num_str);
  337. }
  338. #endif
  339. #endif
  340. //typedef int (*out_func_t)(int c, void *ctx);
  341. //extern void z_vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap);
  342. #include <sys/cbprintf.h>
  343. extern void __vprintk(const char *fmt, va_list ap);
  344. //const char panic_inf[] = "----printk switch to cpu print panic-----\r\n";
  345. #ifdef CONFIG_PRINTK
  346. void vprintk(const char *fmt, va_list args)
  347. {
  348. printk_ctx_t *pctx = &g_pr_ctx;
  349. struct buf_out_ctx ctx_buf;
  350. if (soc_in_sleep_mode()) {
  351. sl_vprintk(fmt, args);
  352. return ;
  353. }
  354. if(!pctx->init){
  355. __vprintk(fmt, args);
  356. return ;
  357. }
  358. if(pctx->panic){
  359. //cbuf_output(panic_inf, sizeof(panic_inf), pctx);
  360. dma_send_sync(pctx);
  361. k_busy_wait(100000); //wait fifo send finshed
  362. uart_dma_switch(pctx, 0, NULL); // CPU
  363. pctx->init = FALSE;
  364. __vprintk(fmt, args);
  365. return;
  366. }
  367. #ifdef CONFIG_PRINTK_TIME_FREFIX
  368. ctx_buf.count = get_time_prefix(ctx_buf.buf);
  369. #else
  370. ctx_buf.count = 0;
  371. #endif
  372. cbvprintf(buf_char_out, &ctx_buf, fmt, args);
  373. ctx_buf_flush(&ctx_buf);
  374. dma_start_tx(pctx);
  375. }
  376. #endif
  377. int uart_dma_send_buf(const uint8_t *buf, int len)
  378. {
  379. printk_ctx_t *pctx = &g_pr_ctx;
  380. int ret;
  381. if(!pctx->init){
  382. k_str_out((char *)buf, len);
  383. return len;
  384. }
  385. ret = cbuf_output(buf ,len, pctx);
  386. dma_start_tx(pctx);
  387. return ret;
  388. }
  389. void cpu_trace_enable(int enable);
  390. void trace_set_panic(void)
  391. {
  392. printk_ctx_t *pctx = &g_pr_ctx;
  393. //printk("$$---trace_set_panic-----##\n");
  394. pctx->panic = 1;
  395. //printk("---trace_set_panic end-----\n");
  396. #ifdef CONFIG_SOC_LEOPARD
  397. cpu_trace_enable(0);
  398. #endif
  399. exception_init();
  400. }
  401. int check_panic_exe(void)
  402. {
  403. return g_pr_ctx.panic;
  404. }
  405. #if defined(CONFIG_STDOUT_CONSOLE)
  406. extern void __stdout_hook_install(int (*hook)(int));
  407. #else
  408. #define __stdout_hook_install(x) \
  409. do { /* nothing */ \
  410. } while ((0))
  411. #endif
  412. static struct buf_out_ctx __act_s2_notsave g_std_buf;
  413. K_MUTEX_DEFINE(std_buf_dma_mutex);
  414. static int dma_std_out(int c)
  415. {
  416. struct buf_out_ctx *ctx = &g_std_buf;
  417. if(!g_pr_ctx.init)
  418. return 0;
  419. k_mutex_lock(&std_buf_dma_mutex, K_FOREVER);
  420. if(ctx->count >= (CTX_TMP_BUF_LEN-2)){
  421. cbuf_output(ctx->buf, ctx->count, &g_pr_ctx);
  422. ctx->count = 0;
  423. }
  424. if ('\n' == c) {
  425. ctx->buf[ctx->count++] = '\r';
  426. ctx->buf[ctx->count++] = c;
  427. cbuf_output(ctx->buf, ctx->count, &g_pr_ctx);
  428. dma_start_tx(&g_pr_ctx);
  429. ctx->count = 0;
  430. }else{
  431. ctx->buf[ctx->count++] = c;
  432. }
  433. k_mutex_unlock(&std_buf_dma_mutex);
  434. return c;
  435. }
  436. void printk_dma_switch(int sw_dma)
  437. {
  438. printk_ctx_t *pctx = &g_pr_ctx;
  439. if(pctx->uart_dev == NULL)
  440. return;
  441. if(sw_dma){
  442. g_std_buf.count = 0;
  443. sl_dbg("printk use dma\n");
  444. uart_dma_switch(pctx, 1, uart_dma_callback);
  445. pctx->init = TRUE;
  446. }else{
  447. sl_dbg("printk use cpu\n");
  448. dma_send_sync(pctx);
  449. #ifdef CONFIG_SLEEP_DBG
  450. k_busy_wait(1000); //wait fifo send finshed
  451. #endif
  452. uart_dma_switch(pctx, 0, NULL); // CPU
  453. pctx->init = FALSE;
  454. }
  455. }
  456. #if defined(CONFIG_PM)
  457. #include <pm/pm.h>
  458. /*call before enter sleep*/
  459. static void printk_pm_notifier_entry(enum pm_state state)
  460. {
  461. printk_dma_switch(0);
  462. #if 0
  463. printk_ctx_t *pctx = &g_pr_ctx;
  464. printk("printk use cpu\n");
  465. dma_send_sync(pctx);
  466. k_busy_wait(1000); //wait fifo send finshed
  467. uart_dma_switch(pctx, 0, NULL); // CPU
  468. pctx->init = FALSE;
  469. #endif
  470. }
  471. /*call after exit sleep*/
  472. static void printk_pm_notifier_exit(enum pm_state state)
  473. {
  474. printk_dma_switch(1);
  475. #if 0
  476. printk_ctx_t *pctx = &g_pr_ctx;
  477. g_std_buf.count = 0;
  478. printk("printk use dma\n");
  479. uart_dma_switch(pctx, 1, uart_dma_callback);
  480. pctx->init = TRUE;
  481. #endif
  482. }
  483. static struct pm_notifier printk_notifier = {
  484. .state_entry = printk_pm_notifier_entry,
  485. .state_exit = printk_pm_notifier_exit,
  486. };
  487. #endif
  488. static int printk_dma_init(const struct device *dev)
  489. {
  490. printk_ctx_t *pctx = &g_pr_ctx;
  491. printk("printk_dma_init\n");
  492. g_std_buf.count = 0;
  493. pctx->uart_dev = (struct device *)device_get_binding(CONFIG_UART_CONSOLE_ON_DEV_NAME);
  494. if(pctx->uart_dev == NULL){
  495. printk("printk_dma_init fail\n");
  496. return -1;
  497. }
  498. cbuf_init(&pctx->cbuf, (void *)dma_printk_buffer, CONFIG_DMA_PRINTK_BUF_SIZE);
  499. if(uart_dma_switch(pctx, 1, uart_dma_callback)) {
  500. printk("printk_dma_init,uart dma not config\n");
  501. return -1;
  502. }
  503. __stdout_hook_install(dma_std_out);
  504. pctx->init = TRUE;
  505. #if defined(CONFIG_PRINTK_TIME_FREFIX)
  506. #ifdef PRINT_US
  507. timer_printk_init();
  508. #endif
  509. #endif
  510. #if defined(CONFIG_PM)
  511. pm_notifier_register(&printk_notifier);
  512. #endif
  513. return 0;
  514. }
  515. SYS_INIT(printk_dma_init, APPLICATION, 1);