vbus.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  1. /*
  2. * COPYRIGHT (C) 2011-2021, Real-Thread Information Technology Ltd
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2013-11-04 Grissiom add comment
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include "vbus.h"
  14. #include "prio_queue.h"
  15. #include "vbus_hw.h"
  16. //#define RT_VBUS_STATISTICS
  17. #define RT_VBUS_RB_LOW_TICK (RT_VMM_RB_BLK_NR * 2 / 3)
  18. #define RT_VBUS_RB_TICK_STEP (100)
  19. /* console could be run on vbus. If we log on it, there will be oops. */
  20. #define vbus_debug(...)
  21. #define vbus_verbose(...)
  22. #define vbus_info(...)
  23. #define vbus_error(...)
  24. #ifndef ARRAY_SIZE
  25. #define ARRAY_SIZE(ar) (sizeof(ar)/sizeof(ar[0]))
  26. #endif
  27. struct rt_vbus_ring *RT_VBUS_OUT_RING;
  28. struct rt_vbus_ring *RT_VBUS_IN_RING;
  29. const char *rt_vbus_chn_st2str[] = {
  30. "available",
  31. "closed",
  32. "establishing",
  33. "established",
  34. "suspended",
  35. "closing",
  36. };
  37. const char *rt_vbus_sess_st2str[] = {
  38. "available",
  39. "listening",
  40. "establishing",
  41. };
  42. const char *rt_vbus_cmd2str[] = {
  43. "ENABLE",
  44. "DISABLE",
  45. "SET",
  46. "ACK",
  47. "NAK",
  48. "SUSPEND",
  49. "RESUME",
  50. };
  51. static char* dump_cmd_pkt(unsigned char *dp, size_t dsize);
  52. /* 4 bytes for the head */
  53. #define LEN2BNR(len) ((len + RT_VBUS_BLK_HEAD_SZ \
  54. + sizeof(struct rt_vbus_blk) - 1) \
  55. / sizeof(struct rt_vbus_blk))
  56. rt_inline void _ring_add_get_bnr(struct rt_vbus_ring *ring,
  57. rt_size_t bnr)
  58. {
  59. int nidx = ring->get_idx + bnr;
  60. if (nidx >= RT_VMM_RB_BLK_NR)
  61. {
  62. nidx -= RT_VMM_RB_BLK_NR;
  63. }
  64. rt_vbus_smp_wmb();
  65. ring->get_idx = nidx;
  66. }
  67. rt_inline int _bus_ring_space_nr(struct rt_vbus_ring *rg)
  68. {
  69. int delta;
  70. rt_vbus_smp_rmb();
  71. delta = rg->get_idx - rg->put_idx;
  72. if (delta > 0)
  73. {
  74. /* Put is behind the get. */
  75. return delta - 1;
  76. }
  77. else
  78. {
  79. /* delta is negative. */
  80. return RT_VMM_RB_BLK_NR + delta - 1;
  81. }
  82. }
  83. struct rt_vbus_pkg {
  84. rt_uint8_t id;
  85. rt_uint8_t prio;
  86. rt_uint8_t finished;
  87. rt_uint8_t len;
  88. const void *data;
  89. };
  90. /* chn0 is always connected */
  91. static enum rt_vbus_chn_status _chn_status[RT_VBUS_CHANNEL_NR];
  92. rt_inline int _chn_connected(unsigned char chnr)
  93. {
  94. return _chn_status[chnr] == RT_VBUS_CHN_ST_ESTABLISHED ||
  95. _chn_status[chnr] == RT_VBUS_CHN_ST_SUSPEND;
  96. }
  97. #ifdef RT_VBUS_USING_FLOW_CONTROL
  98. #include <watermark_queue.h>
  99. struct rt_watermark_queue _chn_wm_que[RT_VBUS_CHANNEL_NR];
  100. void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high)
  101. {
  102. RT_ASSERT((0 < chnr) && (chnr < ARRAY_SIZE(_chn_wm_que)));
  103. rt_wm_que_set_mark(&_chn_wm_que[chnr], low, high);
  104. }
  105. /* Threads suspended by the flow control of other side. */
  106. rt_list_t _chn_suspended_threads[RT_VBUS_CHANNEL_NR];
  107. struct
  108. {
  109. unsigned int level;
  110. unsigned int high_mark;
  111. unsigned int low_mark;
  112. /* The suspend command does not have ACK. So if the other side still
  113. * sending pkg after SUSPEND, warn it again. Also use it as a flag that
  114. * tell me whether are we dropping from the high mark or not when reaching
  115. * the low mark. */
  116. unsigned int last_warn;
  117. } _chn_recv_wm[RT_VBUS_CHANNEL_NR];
  118. void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high)
  119. {
  120. RT_ASSERT((0 < chnr) && (chnr < ARRAY_SIZE(_chn_recv_wm)));
  121. _chn_recv_wm[chnr].low_mark = low;
  122. _chn_recv_wm[chnr].high_mark = high;
  123. }
  124. #else
  125. void rt_vbus_set_recv_wm(unsigned char chnr, unsigned int low, unsigned int high)
  126. {}
  127. void rt_vbus_set_post_wm(unsigned char chnr, unsigned int low, unsigned int high)
  128. {}
  129. #endif
  130. struct {
  131. rt_vbus_event_listener indicate;
  132. void *ctx;
  133. } _vbus_rx_indi[RT_VBUS_EVENT_ID_MAX][RT_VBUS_CHANNEL_NR];
  134. void rt_vbus_register_listener(unsigned char chnr,
  135. enum rt_vbus_event_id eve,
  136. rt_vbus_event_listener indi,
  137. void *ctx)
  138. {
  139. RT_ASSERT(chnr != 0 && chnr < RT_VBUS_CHANNEL_NR);
  140. RT_ASSERT(eve < sizeof(_vbus_rx_indi)/sizeof(_vbus_rx_indi[0]));
  141. _vbus_rx_indi[eve][chnr].indicate = indi;
  142. _vbus_rx_indi[eve][chnr].ctx = ctx;
  143. }
  144. static void _vbus_indicate(enum rt_vbus_event_id eve, unsigned char chnr)
  145. {
  146. RT_ASSERT(eve < sizeof(_vbus_rx_indi)/sizeof(_vbus_rx_indi[0]));
  147. if (_vbus_rx_indi[eve][chnr].indicate)
  148. _vbus_rx_indi[eve][chnr].indicate(_vbus_rx_indi[eve][chnr].ctx);
  149. }
  150. #define _BUS_OUT_THRD_STACK_SZ 2048
  151. #define _BUS_OUT_THRD_PRIO 8
  152. #define _BUS_OUT_PKG_NR RT_VMM_RB_BLK_NR
  153. static struct rt_thread _bus_out_thread;
  154. static rt_uint8_t _bus_out_thread_stack[_BUS_OUT_THRD_STACK_SZ];
  155. struct rt_prio_queue *_bus_out_que;
  156. static void _bus_out_entry(void *param)
  157. {
  158. struct rt_vbus_pkg dpkg;
  159. _bus_out_que = rt_prio_queue_create("vbus",
  160. _BUS_OUT_PKG_NR,
  161. sizeof(struct rt_vbus_pkg));
  162. if (!_bus_out_que)
  163. {
  164. rt_kprintf("could not create vmm bus queue\n");
  165. return;
  166. }
  167. while (rt_prio_queue_pop(_bus_out_que, &dpkg,
  168. RT_WAITING_FOREVER) == RT_EOK)
  169. {
  170. int sp;
  171. rt_uint32_t nxtidx;
  172. const int dnr = LEN2BNR(dpkg.len);
  173. #ifdef RT_VBUS_USING_FLOW_CONTROL
  174. rt_wm_que_dec(&_chn_wm_que[dpkg.id]);
  175. #endif
  176. if (!_chn_connected(dpkg.id))
  177. continue;
  178. sp = _bus_ring_space_nr(RT_VBUS_OUT_RING);
  179. vbus_debug("vmm bus out"
  180. "(data: %p, len: %d, prio: %d, id: %d)\n",
  181. dpkg.data, dpkg.len, dpkg.prio, dpkg.id);
  182. /* wait for enough space */
  183. while (sp < dnr)
  184. {
  185. rt_base_t level = rt_hw_interrupt_disable();
  186. RT_VBUS_OUT_RING->blocked = 1;
  187. rt_vbus_smp_wmb();
  188. /* kick the guest, hoping this could force it do the work */
  189. rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ);
  190. rt_thread_suspend(rt_thread_self());
  191. rt_schedule();
  192. RT_VBUS_OUT_RING->blocked = 0;
  193. rt_hw_interrupt_enable(level);
  194. sp = _bus_ring_space_nr(RT_VBUS_OUT_RING);
  195. }
  196. nxtidx = RT_VBUS_OUT_RING->put_idx + dnr;
  197. RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].id = dpkg.id;
  198. RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].qos = dpkg.prio;
  199. RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].len = dpkg.len;
  200. if (nxtidx >= RT_VMM_RB_BLK_NR)
  201. {
  202. unsigned int tailsz;
  203. tailsz = (RT_VMM_RB_BLK_NR - RT_VBUS_OUT_RING->put_idx)
  204. * sizeof(RT_VBUS_OUT_RING->blks[0]) - RT_VBUS_BLK_HEAD_SZ;
  205. /* the remaining block is sufficient for the data */
  206. if (tailsz > dpkg.len)
  207. tailsz = dpkg.len;
  208. rt_memcpy(&RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].data,
  209. dpkg.data, tailsz);
  210. rt_memcpy(&RT_VBUS_OUT_RING->blks[0],
  211. ((char*)dpkg.data)+tailsz,
  212. dpkg.len - tailsz);
  213. rt_vbus_smp_wmb();
  214. RT_VBUS_OUT_RING->put_idx = nxtidx - RT_VMM_RB_BLK_NR;
  215. }
  216. else
  217. {
  218. rt_memcpy(&RT_VBUS_OUT_RING->blks[RT_VBUS_OUT_RING->put_idx].data,
  219. dpkg.data, dpkg.len);
  220. rt_vbus_smp_wmb();
  221. RT_VBUS_OUT_RING->put_idx = nxtidx;
  222. }
  223. rt_vbus_smp_wmb();
  224. rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ);
  225. if (dpkg.finished)
  226. {
  227. _vbus_indicate(RT_VBUS_EVENT_ID_TX, dpkg.id);
  228. }
  229. }
  230. RT_ASSERT(0);
  231. }
  232. void rt_vbus_resume_out_thread(void)
  233. {
  234. rt_thread_resume(&_bus_out_thread);
  235. rt_schedule();
  236. }
  237. rt_err_t rt_vbus_post(rt_uint8_t id,
  238. rt_uint8_t prio,
  239. const void *data,
  240. rt_size_t size,
  241. rt_int32_t timeout)
  242. {
  243. rt_err_t err = RT_EOK;
  244. struct rt_vbus_pkg pkg;
  245. unsigned int putsz;
  246. const unsigned char *dp;
  247. if (!_bus_out_que)
  248. {
  249. rt_kprintf("post (data: %p, size: %d, timeout: %d) "
  250. "to bus before initialition\n",
  251. data, size, timeout);
  252. return -RT_ERROR;
  253. }
  254. if (id >= RT_VBUS_CHANNEL_NR)
  255. return -RT_ERROR;
  256. if (timeout != 0)
  257. {
  258. RT_DEBUG_IN_THREAD_CONTEXT;
  259. }
  260. #ifdef RT_VBUS_USING_FLOW_CONTROL
  261. while (_chn_status[id] == RT_VBUS_CHN_ST_SUSPEND)
  262. {
  263. rt_thread_t thread;
  264. if (timeout == 0)
  265. {
  266. return -RT_EFULL;
  267. }
  268. thread = rt_thread_self();
  269. thread->error = RT_EOK;
  270. /* We only touch the _chn_suspended_threads in thread, so lock the
  271. * scheduler is enough. */
  272. rt_enter_critical();
  273. rt_thread_suspend(thread);
  274. rt_list_insert_after(&_chn_suspended_threads[id], &RT_THREAD_LIST_NODE(thread));
  275. if (timeout > 0)
  276. {
  277. rt_timer_control(&(thread->thread_timer),
  278. RT_TIMER_CTRL_SET_TIME,
  279. &timeout);
  280. rt_timer_start(&(thread->thread_timer));
  281. }
  282. /* rt_exit_critical will do schedule on need. */
  283. rt_exit_critical();
  284. if (thread->error != RT_EOK)
  285. return thread->error;
  286. }
  287. #endif
  288. if (_chn_status[id] != RT_VBUS_CHN_ST_ESTABLISHED)
  289. return -RT_ERROR;
  290. dp = data;
  291. pkg.id = id;
  292. pkg.prio = prio;
  293. for (putsz = 0; size; size -= putsz)
  294. {
  295. pkg.data = dp;
  296. if (size > RT_VBUS_MAX_PKT_SZ)
  297. {
  298. putsz = RT_VBUS_MAX_PKT_SZ;
  299. pkg.finished = 0;
  300. }
  301. else
  302. {
  303. putsz = size;
  304. pkg.finished = 1;
  305. }
  306. pkg.len = putsz;
  307. dp += putsz;
  308. #ifdef RT_VBUS_USING_FLOW_CONTROL
  309. err = rt_wm_que_inc(&_chn_wm_que[id], timeout);
  310. if (err != RT_EOK)
  311. break;
  312. #endif
  313. vbus_debug("post (data: %p(%d), size: %d, finshed: %d, timeout: %d)\n",
  314. pkg.data, ((unsigned char*)pkg.data)[0],
  315. pkg.len, pkg.finished, timeout);
  316. err = rt_prio_queue_push(_bus_out_que, prio, &pkg, timeout);
  317. if (err != RT_EOK)
  318. break;
  319. }
  320. return err;
  321. }
  322. struct rt_completion _chn0_post_cmp;
  323. void _chn0_tx_listener(void *p)
  324. {
  325. rt_completion_done(&_chn0_post_cmp);
  326. }
  327. /* Posts in channel0 should be sync. */
  328. static rt_err_t _chn0_post(const void *data,
  329. rt_size_t size,
  330. int timeout)
  331. {
  332. rt_err_t err;
  333. rt_completion_init(&_chn0_post_cmp);
  334. err = rt_vbus_post(0, 0, data, size, timeout);
  335. if (err != RT_EOK)
  336. return err;
  337. return rt_completion_wait(&_chn0_post_cmp, timeout);
  338. }
  339. #define _BUS_IN_THRD_STACK_SZ 1024
  340. #define _BUS_IN_THRD_PRIO (_BUS_OUT_THRD_PRIO+1)
  341. #if (_BUS_IN_THRD_PRIO == RT_THREAD_PRIORITY_MAX)
  342. #error "_BUS_OUT_THRD_PRIO too low"
  343. #endif
  344. static struct rt_thread _bus_in_thread;
  345. static rt_uint8_t _bus_in_thread_stack[_BUS_OUT_THRD_STACK_SZ];
  346. static struct rt_semaphore _bus_in_sem;
  347. static struct rt_event _bus_in_event;
  348. /* {head, tail} */
  349. #define _IN_ACT_HEAD 0
  350. #define _IN_ACT_TAIL 1
  351. static struct rt_vbus_data *_bus_in_action[RT_VBUS_CHANNEL_NR][2];
  352. #ifdef RT_VBUS_STATISTICS
  353. static unsigned int _bus_in_action_nr[RT_VBUS_CHANNEL_NR];
  354. #endif
  355. static void rt_vbus_notify_chn(unsigned char chnr, rt_err_t err)
  356. {
  357. #ifdef RT_VBUS_USING_FLOW_CONTROL
  358. /* TODO: get rid of this */
  359. /* Protect the list. */
  360. rt_enter_critical();
  361. while (!rt_list_isempty(&_chn_suspended_threads[chnr]))
  362. {
  363. rt_thread_t thread;
  364. thread = RT_THREAD_LIST_NODE_ENTRY(_chn_suspended_threads[chnr].next);
  365. thread->error = err;
  366. rt_thread_resume(thread);
  367. }
  368. rt_exit_critical();
  369. #endif
  370. rt_event_send(&_bus_in_event, 1 << chnr);
  371. }
  372. static void rt_vbus_notify_set(rt_uint32_t set)
  373. {
  374. rt_event_send(&_bus_in_event, set);
  375. }
  376. rt_err_t rt_vbus_listen_on(rt_uint8_t chnr,
  377. rt_int32_t timeout)
  378. {
  379. rt_uint32_t notuse;
  380. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR || !_chn_connected(chnr))
  381. return -RT_EIO;
  382. return rt_event_recv(&_bus_in_event, 1 << chnr,
  383. RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  384. timeout, &notuse);
  385. }
  386. void rt_vbus_data_push(unsigned int id, struct rt_vbus_data *act)
  387. {
  388. rt_base_t level;
  389. RT_ASSERT(0 < id && id < RT_VBUS_CHANNEL_NR);
  390. level = rt_hw_interrupt_disable();
  391. if (_bus_in_action[id][_IN_ACT_HEAD] == RT_NULL)
  392. {
  393. _bus_in_action[id][_IN_ACT_HEAD] = act;
  394. _bus_in_action[id][_IN_ACT_TAIL] = act;
  395. }
  396. else
  397. {
  398. _bus_in_action[id][_IN_ACT_TAIL]->next = act;
  399. _bus_in_action[id][_IN_ACT_TAIL] = act;
  400. }
  401. #ifdef RT_VBUS_STATISTICS
  402. _bus_in_action_nr[id]++;
  403. #endif
  404. rt_hw_interrupt_enable(level);
  405. #ifdef RT_VBUS_USING_FLOW_CONTROL
  406. _chn_recv_wm[id].level++;
  407. if (_chn_recv_wm[id].level == 0)
  408. _chn_recv_wm[id].level = ~0;
  409. if (_chn_recv_wm[id].level > _chn_recv_wm[id].high_mark &&
  410. _chn_recv_wm[id].level > _chn_recv_wm[id].last_warn)
  411. {
  412. unsigned char buf[2];
  413. buf[0] = RT_VBUS_CHN0_CMD_SUSPEND;
  414. buf[1] = id;
  415. vbus_debug("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf)));
  416. _chn0_post(buf, sizeof(buf), RT_WAITING_FOREVER);
  417. /* Warn the other side in 100 more pkgs. */
  418. _chn_recv_wm[id].last_warn = _chn_recv_wm[id].level + 100;
  419. }
  420. #endif
  421. }
  422. struct rt_vbus_data* rt_vbus_data_pop(unsigned int id)
  423. {
  424. struct rt_vbus_data *act;
  425. rt_base_t level;
  426. RT_ASSERT(0 < id && id < RT_VBUS_CHANNEL_NR);
  427. level = rt_hw_interrupt_disable();
  428. act = _bus_in_action[id][_IN_ACT_HEAD];
  429. if (act)
  430. {
  431. _bus_in_action[id][_IN_ACT_HEAD] = act->next;
  432. }
  433. rt_hw_interrupt_enable(level);
  434. #ifdef RT_VBUS_USING_FLOW_CONTROL
  435. if (_chn_recv_wm[id].level != 0)
  436. {
  437. _chn_recv_wm[id].level--;
  438. if (_chn_recv_wm[id].level <= _chn_recv_wm[id].low_mark &&
  439. _chn_recv_wm[id].last_warn > _chn_recv_wm[id].low_mark)
  440. {
  441. unsigned char buf[2];
  442. buf[0] = RT_VBUS_CHN0_CMD_RESUME;
  443. buf[1] = id;
  444. vbus_debug("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf)));
  445. _chn0_post(buf, sizeof(buf), RT_WAITING_FOREVER);
  446. _chn_recv_wm[id].last_warn = 0;
  447. }
  448. }
  449. #endif
  450. return act;
  451. }
  452. /* dump cmd that is not start with ACK/NAK */
  453. static size_t __dump_naked_cmd(char *dst, size_t lsize,
  454. unsigned char *dp, size_t dsize)
  455. {
  456. size_t len;
  457. if (dp[0] == RT_VBUS_CHN0_CMD_DISABLE ||
  458. dp[0] == RT_VBUS_CHN0_CMD_SUSPEND ||
  459. dp[0] == RT_VBUS_CHN0_CMD_RESUME)
  460. {
  461. len = rt_snprintf(dst, lsize, "%s %d",
  462. rt_vbus_cmd2str[dp[0]], dp[1]);
  463. }
  464. else if (dp[0] == RT_VBUS_CHN0_CMD_ENABLE)
  465. {
  466. len = rt_snprintf(dst, lsize, "%s %s",
  467. rt_vbus_cmd2str[dp[0]], dp+1);
  468. }
  469. else if (dp[0] < RT_VBUS_CHN0_CMD_MAX)
  470. {
  471. len = rt_snprintf(dst, lsize, "%s %s %d",
  472. rt_vbus_cmd2str[dp[0]],
  473. dp+1, dp[2+rt_strlen((char*)dp+1)]);
  474. }
  475. else
  476. {
  477. len = rt_snprintf(dst, lsize, "(invalid)%d %d",
  478. dp[0], dp[1]);
  479. }
  480. return len;
  481. }
  482. static char _cmd_dump_buf[64];
  483. static char* dump_cmd_pkt(unsigned char *dp, size_t dsize)
  484. {
  485. size_t len;
  486. if (dp[0] == RT_VBUS_CHN0_CMD_ACK || dp[0] == RT_VBUS_CHN0_CMD_NAK )
  487. {
  488. len = rt_snprintf(_cmd_dump_buf, sizeof(_cmd_dump_buf),
  489. "%s ", rt_vbus_cmd2str[dp[0]]);
  490. len += __dump_naked_cmd(_cmd_dump_buf+len, sizeof(_cmd_dump_buf)-len,
  491. dp+1, dsize-1);
  492. }
  493. else
  494. {
  495. len = __dump_naked_cmd(_cmd_dump_buf, sizeof(_cmd_dump_buf),
  496. dp, dsize);
  497. }
  498. if (len > sizeof(_cmd_dump_buf) - 1)
  499. len = sizeof(_cmd_dump_buf) - 1;
  500. _cmd_dump_buf[len] = '\0';
  501. return _cmd_dump_buf;
  502. }
  503. static rt_err_t _chn0_echo_with(rt_uint8_t prefix,
  504. rt_uint32_t dsize,
  505. unsigned char *dp)
  506. {
  507. rt_err_t err;
  508. unsigned char *resp;
  509. resp = rt_malloc(dsize+1);
  510. if (!resp)
  511. return -RT_ENOMEM;
  512. *resp = prefix;
  513. rt_memcpy(resp+1, dp, dsize);
  514. vbus_verbose("%s --> remote\n", dump_cmd_pkt(resp, dsize+1));
  515. err = _chn0_post(resp, dsize+1, RT_WAITING_FOREVER);
  516. rt_free(resp);
  517. return err;
  518. }
  519. static rt_err_t _chn0_nak(rt_uint32_t dsize, unsigned char *dp)
  520. {
  521. return _chn0_echo_with(RT_VBUS_CHN0_CMD_NAK, dsize, dp);
  522. }
  523. static rt_err_t _chn0_ack(rt_uint32_t dsize, unsigned char *dp)
  524. {
  525. return _chn0_echo_with(RT_VBUS_CHN0_CMD_ACK, dsize, dp);
  526. }
  527. enum _vbus_session_st
  528. {
  529. SESSIOM_AVAILABLE,
  530. SESSIOM_LISTENING,
  531. SESSIOM_ESTABLISHING,
  532. };
  533. struct rt_vbus_conn_session
  534. {
  535. /* negative value means error */
  536. int chnr;
  537. enum _vbus_session_st st;
  538. struct rt_completion cmp;
  539. struct rt_vbus_request *req;
  540. };
  541. static struct rt_vbus_conn_session _sess[RT_VBUS_CHANNEL_NR/2];
  542. static int _sess_find(const unsigned char *name,
  543. enum _vbus_session_st st)
  544. {
  545. int i;
  546. for (i = 0; i < ARRAY_SIZE(_sess); i++)
  547. {
  548. if (_sess[i].st == st && _sess[i].req->name &&
  549. rt_strcmp(_sess[i].req->name, (char*)name) == 0)
  550. break;
  551. }
  552. return i;
  553. }
  554. static int _chn0_actor(unsigned char *dp, size_t dsize)
  555. {
  556. if (*dp != RT_VBUS_CHN0_CMD_SUSPEND && *dp != RT_VBUS_CHN0_CMD_RESUME)
  557. vbus_verbose("local <-- %s\n", dump_cmd_pkt(dp, dsize));
  558. switch (*dp)
  559. {
  560. case RT_VBUS_CHN0_CMD_ENABLE:
  561. {
  562. int i, chnr;
  563. rt_err_t err;
  564. unsigned char *resp;
  565. i = _sess_find(dp+1, SESSIOM_LISTENING);
  566. if (i == ARRAY_SIZE(_sess))
  567. {
  568. _chn0_nak(dsize, dp);
  569. break;
  570. }
  571. for (chnr = 0; chnr < ARRAY_SIZE(_chn_status); chnr++)
  572. {
  573. if (_chn_status[chnr] == RT_VBUS_CHN_ST_AVAILABLE)
  574. break;
  575. }
  576. if (chnr == ARRAY_SIZE(_chn_status))
  577. {
  578. _chn0_nak(dsize, dp);
  579. break;
  580. }
  581. resp = rt_malloc(dsize + 1);
  582. if (!resp)
  583. break;
  584. *resp = RT_VBUS_CHN0_CMD_SET;
  585. rt_memcpy(resp+1, dp+1, dsize-1);
  586. resp[dsize] = chnr;
  587. rt_vbus_set_recv_wm(chnr, _sess[i].req->recv_wm.low, _sess[i].req->recv_wm.high);
  588. rt_vbus_set_post_wm(chnr, _sess[i].req->post_wm.low, _sess[i].req->post_wm.high);
  589. vbus_verbose("%s --> remote\n", dump_cmd_pkt(resp, dsize+1));
  590. err = _chn0_post(resp, dsize+1, RT_WAITING_FOREVER);
  591. if (err == RT_EOK)
  592. {
  593. _sess[i].st = SESSIOM_ESTABLISHING;
  594. vbus_debug("set sess %d st: %s\n", i,
  595. rt_vbus_sess_st2str[_sess[i].st]);
  596. _sess[i].chnr = chnr;
  597. _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHING;
  598. }
  599. rt_free(resp);
  600. }
  601. break;
  602. case RT_VBUS_CHN0_CMD_SET:
  603. {
  604. int i, chnr;
  605. i = _sess_find(dp+1, SESSIOM_ESTABLISHING);
  606. if (i == ARRAY_SIZE(_sess))
  607. {
  608. vbus_verbose("drop spurious packet\n");
  609. break;
  610. }
  611. chnr = dp[1+rt_strlen((const char*)dp+1)+1];
  612. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  613. {
  614. vbus_verbose("SET wrong chnr %d\n", chnr);
  615. break;
  616. }
  617. if (_chn_status[chnr] != RT_VBUS_CHN_ST_AVAILABLE)
  618. {
  619. _chn0_nak(dsize, dp);
  620. vbus_verbose("SET wrong chnr status %d, %s\n",
  621. chnr, rt_vbus_chn_st2str[_chn_status[chnr]]);
  622. break;
  623. }
  624. rt_vbus_set_recv_wm(chnr, _sess[i].req->recv_wm.low, _sess[i].req->recv_wm.high);
  625. rt_vbus_set_post_wm(chnr, _sess[i].req->post_wm.low, _sess[i].req->post_wm.high);
  626. if (_chn0_ack(dsize, dp) >= 0)
  627. {
  628. _sess[i].chnr = chnr;
  629. _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED;
  630. vbus_debug("chn %d %s\n", chnr,
  631. rt_vbus_chn_st2str[_chn_status[chnr]]);
  632. rt_completion_done(&_sess[i].cmp);
  633. }
  634. }
  635. break;
  636. case RT_VBUS_CHN0_CMD_ACK:
  637. if (dp[1] == RT_VBUS_CHN0_CMD_SET)
  638. {
  639. int i, chnr;
  640. i = _sess_find(dp+2, SESSIOM_ESTABLISHING);
  641. if (i == ARRAY_SIZE(_sess))
  642. /* drop that spurious packet */
  643. break;
  644. chnr = dp[1+rt_strlen((const char*)dp+2)+2];
  645. _sess[i].chnr = chnr;
  646. _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED;
  647. vbus_debug("chn %d %s\n", chnr,
  648. rt_vbus_chn_st2str[_chn_status[chnr]]);
  649. rt_completion_done(&_sess[i].cmp);
  650. }
  651. else if (dp[1] == RT_VBUS_CHN0_CMD_DISABLE)
  652. {
  653. unsigned char chnr = dp[2];
  654. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  655. break;
  656. /* We could only get here by sending DISABLE command, which is
  657. * initiated by the rt_vbus_close_chn. */
  658. _chn_status[chnr] = RT_VBUS_CHN_ST_AVAILABLE;
  659. _vbus_indicate(RT_VBUS_EVENT_ID_DISCONN, chnr);
  660. /* notify the thread that the channel has been closed */
  661. rt_vbus_notify_chn(chnr, -RT_ERROR);
  662. }
  663. else
  664. {
  665. vbus_info("invalid ACK for %d\n", dp[1]);
  666. }
  667. break;
  668. case RT_VBUS_CHN0_CMD_DISABLE:
  669. {
  670. unsigned char chnr = dp[1];
  671. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  672. break;
  673. _chn_status[chnr] = RT_VBUS_CHN_ST_CLOSING;
  674. _chn0_ack(dsize, dp);
  675. _vbus_indicate(RT_VBUS_EVENT_ID_DISCONN, chnr);
  676. /* notify the thread that the channel has been closed */
  677. rt_vbus_notify_chn(chnr, -RT_ERROR);
  678. }
  679. break;
  680. case RT_VBUS_CHN0_CMD_SUSPEND:
  681. #ifdef RT_VBUS_USING_FLOW_CONTROL
  682. {
  683. unsigned char chnr = dp[1];
  684. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  685. break;
  686. if (_chn_status[chnr] != RT_VBUS_CHN_ST_ESTABLISHED)
  687. break;
  688. _chn_status[chnr] = RT_VBUS_CHN_ST_SUSPEND;
  689. }
  690. #endif
  691. break;
  692. case RT_VBUS_CHN0_CMD_RESUME:
  693. #ifdef RT_VBUS_USING_FLOW_CONTROL
  694. {
  695. unsigned char chnr = dp[1];
  696. if (chnr == 0 || chnr >= RT_VBUS_CHANNEL_NR)
  697. break;
  698. if (_chn_status[chnr] != RT_VBUS_CHN_ST_SUSPEND)
  699. break;
  700. _chn_status[chnr] = RT_VBUS_CHN_ST_ESTABLISHED;
  701. /* Protect the list. */
  702. rt_enter_critical();
  703. while (!rt_list_isempty(&_chn_suspended_threads[chnr]))
  704. {
  705. rt_thread_t thread;
  706. thread = RT_THREAD_LIST_NODE_ENTRY(_chn_suspended_threads[chnr].next);
  707. rt_thread_resume(thread);
  708. }
  709. rt_exit_critical();
  710. }
  711. #endif
  712. break;
  713. case RT_VBUS_CHN0_CMD_NAK:
  714. if (dp[1] == RT_VBUS_CHN0_CMD_ENABLE)
  715. {
  716. int i;
  717. i = _sess_find(dp+2, SESSIOM_ESTABLISHING);
  718. if (i == ARRAY_SIZE(_sess))
  719. /* drop that spurious packet */
  720. break;
  721. _sess[i].chnr = -RT_EIO;
  722. rt_completion_done(&_sess[i].cmp);
  723. }
  724. else if (dp[1] == RT_VBUS_CHN0_CMD_SET)
  725. {
  726. vbus_info("NAK for %d not implemented\n", dp[1]);
  727. }
  728. else
  729. {
  730. vbus_info("invalid NAK for %d\n", dp[1]);
  731. }
  732. break;
  733. default:
  734. /* just ignore the invalid cmd */
  735. vbus_info("drop unknown cmd %d on chn0\n", *dp);
  736. break;
  737. };
  738. return RT_EOK;
  739. }
  740. int rt_vbus_request_chn(struct rt_vbus_request *req,
  741. int timeout)
  742. {
  743. int i, chnr, err;
  744. size_t plen = rt_strlen(req->name) + 2;
  745. unsigned char *pbuf;
  746. rt_base_t level;
  747. level = rt_hw_interrupt_disable();
  748. for (i = 0; i < ARRAY_SIZE(_sess); i++)
  749. {
  750. if (_sess[i].st == SESSIOM_AVAILABLE)
  751. break;
  752. }
  753. if (i == ARRAY_SIZE(_sess))
  754. {
  755. rt_hw_interrupt_enable(level);
  756. return -RT_ERROR;
  757. }
  758. rt_completion_init(&_sess[i].cmp);
  759. _sess[i].req = req;
  760. if (req->is_server)
  761. {
  762. _sess[i].st = SESSIOM_LISTENING;
  763. rt_hw_interrupt_enable(level);
  764. vbus_debug("request listening %s on %d\n", req->name, i);
  765. /* always wait on the condition */
  766. err = RT_EOK;
  767. goto _waitforcmp;
  768. }
  769. pbuf = rt_malloc(plen);
  770. if (!pbuf)
  771. {
  772. rt_hw_interrupt_enable(level);
  773. return -RT_ENOMEM;
  774. }
  775. _sess[i].st = SESSIOM_ESTABLISHING;
  776. rt_hw_interrupt_enable(level);
  777. pbuf[0] = RT_VBUS_CHN0_CMD_ENABLE;
  778. rt_memcpy(pbuf+1, req->name, plen-1);
  779. vbus_verbose("%s --> remote\n", dump_cmd_pkt(pbuf, plen));
  780. err = _chn0_post(pbuf, plen, RT_WAITING_FOREVER);
  781. rt_free(pbuf);
  782. _waitforcmp:
  783. if (err == RT_EOK)
  784. err = rt_completion_wait(&_sess[i].cmp, timeout);
  785. vbus_debug("request wait cmp done %d, chnr %d\n", err, _sess[i].chnr);
  786. if (err)
  787. {
  788. /* cleanup the mass when the wait is time out but we have done some job
  789. */
  790. if (_sess[i].st == SESSIOM_ESTABLISHING)
  791. _chn_status[_sess[i].chnr] = RT_VBUS_CHN_ST_AVAILABLE;
  792. chnr = err;
  793. goto Out;
  794. }
  795. RT_ASSERT(_sess[i].chnr != 0);
  796. chnr = _sess[i].chnr;
  797. Out:
  798. /* detach the sess as we finished the job */
  799. _sess[i].st = SESSIOM_AVAILABLE;
  800. _sess[i].req = RT_NULL;
  801. return chnr;
  802. }
  803. void rt_vbus_close_chn(unsigned char chnr)
  804. {
  805. void *p;
  806. rt_err_t err;
  807. unsigned char buf[2];
  808. buf[0] = RT_VBUS_CHN0_CMD_DISABLE;
  809. buf[1] = chnr;
  810. RT_ASSERT(0 < chnr && chnr < RT_VBUS_CHANNEL_NR);
  811. if (_chn_status[chnr] == RT_VBUS_CHN_ST_CLOSED ||
  812. _chn_status[chnr] == RT_VBUS_CHN_ST_CLOSING)
  813. {
  814. _chn_status[chnr] = RT_VBUS_CHN_ST_AVAILABLE;
  815. return;
  816. }
  817. if (!_chn_connected(chnr))
  818. return;
  819. _chn_status[chnr] = RT_VBUS_CHN_ST_CLOSING;
  820. vbus_info("%s --> remote\n", dump_cmd_pkt(buf, sizeof(buf)));
  821. err = _chn0_post(&buf, sizeof(buf), RT_WAITING_FOREVER);
  822. if (err == RT_EOK)
  823. /* wait for the ack */
  824. rt_vbus_listen_on(chnr, 10 * RT_TICK_PER_SECOND);
  825. /* cleanup the remaining data */
  826. for (p = rt_vbus_data_pop(chnr); p; p = rt_vbus_data_pop(chnr))
  827. rt_free(p);
  828. /* FIXME: there is a chance that there are some data left on the send
  829. * buffer. So if we connect other channel with the same number immediately,
  830. * the new channel will receive some garbage data. However, this is highly
  831. * un-probable. */
  832. }
  833. #ifdef RT_VBUS_STATISTICS
  834. static unsigned int _total_data_sz;
  835. #endif
  836. static void _bus_in_entry(void *param)
  837. {
  838. rt_sem_init(&_bus_in_sem, "vbus", 0, RT_IPC_FLAG_FIFO);
  839. rt_event_init(&_bus_in_event, "vbus", RT_IPC_FLAG_FIFO);
  840. rt_memset(_bus_in_action, 0, sizeof(_bus_in_action));
  841. while (rt_sem_take(&_bus_in_sem,
  842. RT_WAITING_FOREVER) == RT_EOK)
  843. {
  844. rt_uint32_t event_set = 0;
  845. /* while(not empty) */
  846. while (RT_VBUS_IN_RING->get_idx != RT_VBUS_IN_RING->put_idx)
  847. {
  848. unsigned int id, nxtidx;
  849. rt_size_t size;
  850. struct rt_vbus_data *act;
  851. rt_vbus_smp_rmb();
  852. size = RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].len;
  853. id = RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].id;
  854. vbus_debug("vmm bus in: chnr %d, size %d\n", id, size);
  855. /* Suspended channel can still recv data. */
  856. if (id > RT_VBUS_CHANNEL_NR || !_chn_connected(id))
  857. {
  858. vbus_error("drop on invalid chn %d\n", id);
  859. /* drop the invalid packet */
  860. _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size));
  861. continue;
  862. }
  863. if (id == 0)
  864. {
  865. if (size > 60)
  866. vbus_error("too big(%d) packet on chn0\n", size);
  867. else
  868. _chn0_actor(RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, size);
  869. _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size));
  870. continue;
  871. }
  872. #ifdef RT_VBUS_STATISTICS
  873. _total_data_sz += size;
  874. #endif
  875. act = rt_malloc(sizeof(*act) + size);
  876. if (act == RT_NULL)
  877. {
  878. //vbus_error("drop on OOM (%d, %d)\n", id, size);
  879. /* drop the packet on malloc fall */
  880. _ring_add_get_bnr(RT_VBUS_IN_RING, LEN2BNR(size));
  881. continue;
  882. }
  883. act->size = size;
  884. act->next = RT_NULL;
  885. nxtidx = RT_VBUS_IN_RING->get_idx + LEN2BNR(size);
  886. if (nxtidx >= RT_VMM_RB_BLK_NR)
  887. {
  888. unsigned int tailsz;
  889. tailsz = (RT_VMM_RB_BLK_NR - RT_VBUS_IN_RING->get_idx)
  890. * sizeof(RT_VBUS_IN_RING->blks[0]) - RT_VBUS_BLK_HEAD_SZ;
  891. /* the remaining block is sufficient for the data */
  892. if (tailsz > size)
  893. tailsz = size;
  894. rt_memcpy(act+1, &RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, tailsz);
  895. rt_memcpy((char*)(act+1) + tailsz, &RT_VBUS_IN_RING->blks[0], size - tailsz);
  896. /* It shall make sure the CPU has finished reading the item
  897. * before it writes the new tail pointer, which will erase the
  898. * item. */
  899. rt_vbus_smp_wmb();
  900. RT_VBUS_IN_RING->get_idx = nxtidx - RT_VMM_RB_BLK_NR;
  901. }
  902. else
  903. {
  904. rt_memcpy(act+1, &RT_VBUS_IN_RING->blks[RT_VBUS_IN_RING->get_idx].data, size);
  905. rt_vbus_smp_wmb();
  906. RT_VBUS_IN_RING->get_idx = nxtidx;
  907. }
  908. rt_vbus_data_push(id, act);
  909. _vbus_indicate(RT_VBUS_EVENT_ID_RX, id);
  910. event_set |= 1 << id;
  911. if (RT_VBUS_IN_RING->blocked)
  912. rt_vbus_tick(0, RT_VBUS_GUEST_VIRQ);
  913. }
  914. if (event_set != 0)
  915. rt_vbus_notify_set(event_set);
  916. }
  917. RT_ASSERT(0);
  918. }
  919. void rt_vbus_isr(int irqnr, void *param)
  920. {
  921. if (RT_VBUS_OUT_RING->blocked)
  922. rt_vbus_resume_out_thread();
  923. rt_sem_release(&_bus_in_sem);
  924. rt_vbus_hw_eoi(irqnr, param);
  925. }
  926. int rt_vbus_init(void *outr, void *inr)
  927. {
  928. int i;
  929. if (outr > inr)
  930. {
  931. RT_ASSERT((char*)outr - (char*)inr >= sizeof(struct rt_vbus_ring));
  932. }
  933. else
  934. {
  935. RT_ASSERT((char*)inr - (char*)outr >= sizeof(struct rt_vbus_ring));
  936. }
  937. RT_VBUS_OUT_RING = outr;
  938. RT_VBUS_IN_RING = inr;
  939. rt_memset(RT_VBUS_OUT_RING, 0, sizeof(*RT_VBUS_OUT_RING));
  940. rt_memset(RT_VBUS_IN_RING, 0, sizeof(*RT_VBUS_IN_RING));
  941. _chn_status[0] = RT_VBUS_CHN_ST_ESTABLISHED;
  942. for (i = 1; i < ARRAY_SIZE(_chn_status); i++)
  943. {
  944. _chn_status[i] = RT_VBUS_CHN_ST_AVAILABLE;
  945. }
  946. for (i = 0; i < ARRAY_SIZE(_sess); i++)
  947. {
  948. _sess[i].req = RT_NULL;
  949. _sess[i].st = SESSIOM_AVAILABLE;
  950. }
  951. _vbus_rx_indi[RT_VBUS_EVENT_ID_TX][0].indicate = _chn0_tx_listener;
  952. _vbus_rx_indi[RT_VBUS_EVENT_ID_TX][0].ctx = RT_NULL;
  953. #ifdef RT_VBUS_USING_FLOW_CONTROL
  954. for (i = 0; i < ARRAY_SIZE(_chn_wm_que); i++)
  955. {
  956. rt_wm_que_init(&_chn_wm_que[i],
  957. RT_VMM_RB_BLK_NR / 3,
  958. RT_VMM_RB_BLK_NR * 2 / 3);
  959. }
  960. /* Channel 0 has the full channel. */
  961. rt_wm_que_set_mark(&_chn_wm_que[0], 0, ~0);
  962. for (i = 0; i < ARRAY_SIZE(_chn_suspended_threads); i++)
  963. {
  964. rt_list_init(&_chn_suspended_threads[i]);
  965. }
  966. for (i = 1; i < ARRAY_SIZE(_chn_recv_wm); i++)
  967. {
  968. rt_vbus_set_recv_wm(i,
  969. RT_VMM_RB_BLK_NR / 3,
  970. RT_VMM_RB_BLK_NR * 2 / 3);
  971. _chn_recv_wm[i].level = 0;
  972. _chn_recv_wm[i].last_warn = 0;
  973. }
  974. /* Channel 0 has the full channel. Don't suspend it. */
  975. _chn_recv_wm[0].low_mark = 0;
  976. _chn_recv_wm[0].high_mark = ~0;
  977. _chn_recv_wm[0].level = 0;
  978. _chn_recv_wm[0].last_warn = 0;
  979. #endif
  980. rt_thread_init(&_bus_out_thread, "vbusout",
  981. _bus_out_entry, RT_NULL,
  982. _bus_out_thread_stack, sizeof(_bus_out_thread_stack),
  983. _BUS_OUT_THRD_PRIO, 20);
  984. rt_thread_startup(&_bus_out_thread);
  985. rt_thread_init(&_bus_in_thread, "vbusin",
  986. _bus_in_entry, RT_NULL,
  987. _bus_in_thread_stack, sizeof(_bus_in_thread_stack),
  988. _BUS_IN_THRD_PRIO, 20);
  989. rt_thread_startup(&_bus_in_thread);
  990. rt_vbus_hw_init();
  991. rt_kprintf("VBus loaded: %d out blocks, %d in blocks\n",
  992. RT_VMM_RB_BLK_NR, RT_VMM_RB_BLK_NR);
  993. rt_vbus_chnx_init();
  994. return 0;
  995. }
  996. void rt_vbus_rb_dump(void)
  997. {
  998. rt_kprintf("OUT ring:(%s blocked)\n", RT_VBUS_OUT_RING->blocked ? "is" : "not");
  999. rt_kprintf("put idx: %8x, get idx: %8x\n",
  1000. RT_VBUS_OUT_RING->put_idx, RT_VBUS_OUT_RING->get_idx);
  1001. rt_kprintf("space: %d\n", _bus_ring_space_nr(RT_VBUS_OUT_RING));
  1002. rt_kprintf("IN ring:(%s blocked)\n", RT_VBUS_IN_RING->blocked ? "is" : "not");
  1003. rt_kprintf("put idx: %8x, get idx: %8x\n",
  1004. RT_VBUS_IN_RING->put_idx, RT_VBUS_IN_RING->get_idx);
  1005. rt_kprintf("space: %d\n", _bus_ring_space_nr(RT_VBUS_IN_RING));
  1006. }
  1007. void rt_vbus_chn_dump(void)
  1008. {
  1009. int i;
  1010. rt_kprintf("vbus channel status:\n");
  1011. for (i = 0; i < ARRAY_SIZE(_chn_status); i++)
  1012. {
  1013. rt_kprintf("%2d:%s\n", i, rt_vbus_chn_st2str[_chn_status[i]]);
  1014. }
  1015. }
  1016. void rt_vbus_sess_dump(void)
  1017. {
  1018. int i;
  1019. rt_kprintf("vbus conn session:\n");
  1020. for (i = 0; i < ARRAY_SIZE(_sess); i++)
  1021. {
  1022. rt_kprintf("%2d(%s):%s\n", i, _sess[i].req ? _sess[i].req->name : "",
  1023. rt_vbus_sess_st2str[_sess[i].st]);
  1024. }
  1025. }
  1026. void rt_vbus_que_dump(void)
  1027. {
  1028. rt_kprintf("out que:\n");
  1029. rt_prio_queue_dump(_bus_out_que);
  1030. }
  1031. unsigned int rt_vbus_total_data_sz(void)
  1032. {
  1033. #ifdef RT_VBUS_STATISTICS
  1034. return _total_data_sz;
  1035. #else
  1036. return (unsigned int)-1;
  1037. #endif
  1038. }
  1039. void rt_vbus_data_pkt_dump(void)
  1040. {
  1041. int i;
  1042. for (i = 0; i < ARRAY_SIZE(_bus_in_action); i++)
  1043. {
  1044. struct rt_vbus_data *dp;
  1045. #ifdef RT_VBUS_STATISTICS
  1046. rt_kprintf("%2d %4d: ", i, _bus_in_action_nr[i]);
  1047. #else
  1048. rt_kprintf("%2d: ", i);
  1049. #endif
  1050. for (dp = _bus_in_action[i][_IN_ACT_HEAD];
  1051. dp;
  1052. dp = dp->next)
  1053. {
  1054. rt_kprintf("%p(%d) -> ", dp, dp->size);
  1055. }
  1056. rt_kprintf(" nil\n");
  1057. }
  1058. }
  1059. #ifdef RT_VBUS_USING_FLOW_CONTROL
  1060. void rt_vbus_chm_wm_dump(void)
  1061. {
  1062. int i;
  1063. rt_kprintf("post wm:\n");
  1064. for (i = 0; i < ARRAY_SIZE(_chn_wm_que); i++)
  1065. rt_wm_que_dump(&_chn_wm_que[i]);
  1066. rt_kprintf("recv wm:\n");
  1067. rt_kprintf(" low, high, cur, last warn\n");
  1068. for (i = 0; i < ARRAY_SIZE(_chn_recv_wm); i++)
  1069. {
  1070. rt_kprintf("%8x, %8x, %8x, %8x\n",
  1071. _chn_recv_wm[i].low_mark, _chn_recv_wm[i].high_mark,
  1072. _chn_recv_wm[i].level, _chn_recv_wm[i].last_warn);
  1073. }
  1074. }
  1075. #endif
  1076. #ifdef RT_USING_FINSH
  1077. #include <finsh.h>
  1078. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_rb_dump, vbrb, dump vbus ringbuffer status);
  1079. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_chn_dump, vbchn, dump vbus channel status);
  1080. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_sess_dump, vbses, dump vbus session status);
  1081. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_que_dump, vbque, dump vbus out queue status);
  1082. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_total_data_sz, vbtsz, total in data);
  1083. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_data_pkt_dump, vbdq, dump the data queue);
  1084. #ifdef RT_VBUS_USING_FLOW_CONTROL
  1085. FINSH_FUNCTION_EXPORT_ALIAS(rt_vbus_chm_wm_dump, vbwm, dump vbus water mark status);
  1086. #endif
  1087. #endif