virtio_console.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021-11-11 GuEe-GUI the first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <cpuport.h>
  13. #ifdef RT_USING_VIRTIO_CONSOLE
  14. #include <virtio_console.h>
  15. struct port_device
  16. {
  17. struct rt_device parent;
  18. rt_list_t node;
  19. rt_uint32_t port_id;
  20. rt_bool_t rx_notify;
  21. rt_bool_t need_destroy;
  22. struct virtio_console_device *console;
  23. struct virtq *queue_rx, *queue_tx;
  24. rt_uint32_t queue_rx_index, queue_tx_index;
  25. #ifdef RT_USING_SMP
  26. struct rt_spinlock spinlock_rx, spinlock_tx;
  27. #endif
  28. struct
  29. {
  30. char rx_char, tx_char;
  31. } info[VIRTIO_CONSOLE_QUEUE_SIZE];
  32. };
  33. static void virtio_console_send_ctrl(struct virtio_console_device *virtio_console_dev,
  34. struct virtio_console_control *ctrl)
  35. {
  36. rt_uint16_t id;
  37. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  38. struct virtq *queue_ctrl_tx;
  39. #ifdef RT_USING_SMP
  40. rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  41. #endif
  42. queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
  43. id = queue_ctrl_tx->avail->idx % queue_ctrl_tx->num;
  44. rt_memcpy(&virtio_console_dev->info[id].tx_ctrl, ctrl, sizeof(struct virtio_console_control));
  45. virtio_free_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
  46. virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id,
  47. virtio_console_dev->info[id].tx_ctrl_paddr, sizeof(struct virtio_console_control), 0, 0);
  48. virtio_submit_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
  49. virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
  50. virtio_alloc_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
  51. #ifdef RT_USING_SMP
  52. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  53. #endif
  54. }
  55. static rt_err_t virtio_console_port_create(struct virtio_console_device *virtio_console_dev,
  56. const struct rt_device_ops *ops)
  57. {
  58. rt_uint32_t port_id;
  59. char dev_name[RT_NAME_MAX];
  60. struct port_device *port_dev, *prev_port_dev = RT_NULL;
  61. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  62. if (virtio_console_dev->port_nr > 0 && !virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  63. {
  64. return -RT_ENOSYS;
  65. }
  66. if (virtio_console_dev->port_nr >= virtio_console_dev->max_port_nr)
  67. {
  68. return -RT_EFULL;
  69. }
  70. port_id = 0;
  71. /* The port device list is always ordered, so just find next number for id */
  72. rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
  73. {
  74. if (port_dev->port_id != port_id)
  75. {
  76. break;
  77. }
  78. ++port_id;
  79. prev_port_dev = port_dev;
  80. }
  81. port_dev = rt_malloc(sizeof(struct port_device));
  82. if (port_dev == RT_NULL)
  83. {
  84. return -RT_ENOMEM;
  85. }
  86. port_dev->parent.type = RT_Device_Class_Char;
  87. port_dev->parent.ops = ops;
  88. port_dev->parent.rx_indicate = RT_NULL;
  89. port_dev->parent.tx_complete = RT_NULL;
  90. rt_list_init(&port_dev->node);
  91. port_dev->port_id = port_id;
  92. port_dev->need_destroy = RT_FALSE;
  93. port_dev->rx_notify = RT_TRUE;
  94. port_dev->console = virtio_console_dev;
  95. port_dev->queue_rx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
  96. port_dev->queue_tx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
  97. port_dev->queue_rx = &virtio_dev->queues[port_dev->queue_rx_index];
  98. port_dev->queue_tx = &virtio_dev->queues[port_dev->queue_tx_index];
  99. #ifdef RT_USING_SMP
  100. rt_spin_lock_init(&port_dev->spinlock_rx);
  101. rt_spin_lock_init(&port_dev->spinlock_tx);
  102. #endif
  103. rt_snprintf(dev_name, RT_NAME_MAX, "vport%dp%d", virtio_console_dev->console_id, port_id);
  104. if (rt_device_register((rt_device_t)port_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX) != RT_EOK)
  105. {
  106. rt_free(port_dev);
  107. return -RT_ERROR;
  108. }
  109. if (prev_port_dev != RT_NULL)
  110. {
  111. rt_list_insert_after(&prev_port_dev->node, &port_dev->node);
  112. }
  113. else
  114. {
  115. /* Port0 */
  116. rt_list_insert_after(&virtio_console_dev->port_head, &port_dev->node);
  117. }
  118. virtio_console_dev->port_nr++;
  119. return RT_EOK;
  120. }
  121. static void virtio_console_port_destroy(struct virtio_console_device *virtio_console_dev,
  122. struct port_device *port_dev)
  123. {
  124. struct virtio_console_control set_ctrl;
  125. set_ctrl.id = port_dev->port_id;
  126. set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
  127. set_ctrl.value = 0;
  128. virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
  129. virtio_console_dev->port_nr--;
  130. rt_list_remove(&port_dev->node);
  131. rt_device_unregister((rt_device_t)port_dev);
  132. rt_free(port_dev);
  133. }
  134. static rt_err_t virtio_console_port_init(rt_device_t dev)
  135. {
  136. rt_uint16_t id;
  137. rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
  138. rt_uint16_t rx_queue_index, tx_queue_index;
  139. struct port_device *port_dev = (struct port_device *)dev;
  140. struct virtio_console_device *virtio_console_dev = port_dev->console;
  141. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  142. struct virtq *queue_rx, *queue_tx;
  143. rx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
  144. tx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
  145. queue_rx = &virtio_dev->queues[rx_queue_index];
  146. queue_tx = &virtio_dev->queues[tx_queue_index];
  147. virtio_alloc_desc_chain(virtio_dev, rx_queue_index, queue_rx->num, idx);
  148. virtio_alloc_desc_chain(virtio_dev, tx_queue_index, queue_tx->num, idx);
  149. for (id = 0; id < queue_rx->num; ++id)
  150. {
  151. void *addr = &port_dev->info[id].rx_char;
  152. virtio_fill_desc(virtio_dev, rx_queue_index, id,
  153. VIRTIO_VA2PA(addr), sizeof(char), VIRTQ_DESC_F_WRITE, 0);
  154. queue_rx->avail->ring[id] = id;
  155. }
  156. rt_hw_dsb();
  157. queue_rx->avail->flags = 0;
  158. queue_rx->avail->idx = queue_rx->num;
  159. queue_rx->used_idx = queue_rx->used->idx;
  160. queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
  161. queue_tx->avail->idx = 0;
  162. virtio_queue_notify(virtio_dev, rx_queue_index);
  163. if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  164. {
  165. struct virtio_console_control set_ctrl;
  166. set_ctrl.id = VIRTIO_CONSOLE_PORT_BAD_ID;
  167. set_ctrl.event = VIRTIO_CONSOLE_DEVICE_READY;
  168. set_ctrl.value = 1;
  169. virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
  170. }
  171. return RT_EOK;
  172. }
  173. static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag)
  174. {
  175. struct port_device *port_dev = (struct port_device *)dev;
  176. /* Can't use by others, just support only one */
  177. if (port_dev->parent.ref_count > 1)
  178. {
  179. return -RT_EBUSY;
  180. }
  181. if (port_dev->port_id == 0 && virtio_has_feature(&port_dev->console->virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  182. {
  183. /* Port0 is reserve in multiport */
  184. return -RT_ERROR;
  185. }
  186. port_dev->rx_notify = RT_TRUE;
  187. return RT_EOK;
  188. }
  189. static rt_err_t virtio_console_port_close(rt_device_t dev)
  190. {
  191. struct port_device *port_dev = (struct port_device *)dev;
  192. if (port_dev->need_destroy)
  193. {
  194. virtio_console_port_destroy(port_dev->console, port_dev);
  195. /*
  196. * We released the device memory in virtio_console_port_destroy,
  197. * rt_device_close has not finished yet, make the return value
  198. * to empty so that rt_device_close will not access the device memory.
  199. */
  200. return -RT_EEMPTY;
  201. }
  202. port_dev->rx_notify = RT_FALSE;
  203. return RT_EOK;
  204. }
  205. static rt_size_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
  206. {
  207. rt_off_t i = 0;
  208. rt_uint16_t id;
  209. rt_uint32_t len;
  210. struct port_device *port_dev = (struct port_device *)dev;
  211. struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
  212. rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
  213. struct virtq *queue_rx = port_dev->queue_rx;
  214. #ifdef RT_USING_SMP
  215. rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
  216. #endif
  217. while (i < size)
  218. {
  219. if (queue_rx->used_idx == queue_rx->used->idx)
  220. {
  221. break;
  222. }
  223. rt_hw_dsb();
  224. id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
  225. len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
  226. if (len > sizeof(char))
  227. {
  228. rt_kprintf("%s: Receive buffer's size = %u is too big!\n", port_dev->parent.parent.name, len);
  229. len = sizeof(char);
  230. }
  231. *((char *)buffer + i) = port_dev->info[id].rx_char;
  232. queue_rx->used_idx++;
  233. virtio_submit_chain(virtio_dev, queue_rx_index, id);
  234. virtio_queue_notify(virtio_dev, queue_rx_index);
  235. i += len;
  236. }
  237. #ifdef RT_USING_SMP
  238. rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
  239. #endif
  240. size = i;
  241. return size;
  242. }
  243. static rt_size_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
  244. {
  245. char ch = 0;
  246. rt_off_t i = 0;
  247. rt_uint16_t id;
  248. struct port_device *port_dev = (struct port_device *)dev;
  249. struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
  250. rt_uint32_t queue_tx_index = port_dev->queue_tx_index;
  251. struct virtq *queue_tx = port_dev->queue_tx;
  252. #ifdef RT_USING_SMP
  253. rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_tx);
  254. #endif
  255. while (i < size || ch == '\r')
  256. {
  257. id = queue_tx->avail->idx % queue_tx->num;
  258. /* Keep the way until 'new line' are unified */
  259. if (ch != '\r')
  260. {
  261. ch = *((const char *)buffer + i);
  262. }
  263. else
  264. {
  265. i -= sizeof(char);
  266. }
  267. port_dev->info[id].tx_char = ch;
  268. ch = (ch == '\n' ? '\r' : 0);
  269. virtio_free_desc(virtio_dev, queue_tx_index, id);
  270. virtio_fill_desc(virtio_dev, queue_tx_index, id,
  271. VIRTIO_VA2PA(&port_dev->info[id].tx_char), sizeof(char), 0, 0);
  272. virtio_submit_chain(virtio_dev, queue_tx_index, id);
  273. virtio_queue_notify(virtio_dev, queue_tx_index);
  274. virtio_alloc_desc(virtio_dev, queue_tx_index);
  275. i += sizeof(char);
  276. }
  277. #ifdef RT_USING_SMP
  278. rt_spin_unlock_irqrestore(&port_dev->spinlock_tx, level);
  279. #endif
  280. return size;
  281. }
  282. static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args)
  283. {
  284. rt_err_t status = RT_EOK;
  285. struct port_device *port_dev = (struct port_device *)dev;
  286. switch (cmd)
  287. {
  288. case RT_DEVICE_CTRL_CLR_INT:
  289. /* Disable RX */
  290. port_dev->rx_notify = RT_FALSE;
  291. break;
  292. case RT_DEVICE_CTRL_SET_INT:
  293. /* Enable RX */
  294. port_dev->rx_notify = RT_TRUE;
  295. break;
  296. case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY:
  297. {
  298. port_dev->need_destroy = RT_TRUE;
  299. port_dev->rx_notify = RT_FALSE;
  300. }
  301. break;
  302. default:
  303. status = -RT_EINVAL;
  304. break;
  305. }
  306. return status;
  307. }
  308. const static struct rt_device_ops virtio_console_port_ops =
  309. {
  310. virtio_console_port_init,
  311. virtio_console_port_open,
  312. virtio_console_port_close,
  313. virtio_console_port_read,
  314. virtio_console_port_write,
  315. virtio_console_port_control
  316. };
  317. static rt_err_t virtio_console_init(rt_device_t dev)
  318. {
  319. struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
  320. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  321. if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  322. {
  323. rt_uint16_t id;
  324. rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
  325. struct virtq *queue_ctrl_rx, *queue_ctrl_tx;
  326. queue_ctrl_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
  327. queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
  328. virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, queue_ctrl_rx->num, idx);
  329. virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, queue_ctrl_tx->num, idx);
  330. for (id = 0; id < queue_ctrl_rx->num; ++id)
  331. {
  332. void *addr = &virtio_console_dev->info[id].rx_ctrl;
  333. virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, id,
  334. VIRTIO_VA2PA(addr), sizeof(struct virtio_console_control), VIRTQ_DESC_F_WRITE, 0);
  335. queue_ctrl_rx->avail->ring[id] = id;
  336. }
  337. rt_hw_dsb();
  338. for (id = 0; id < queue_ctrl_tx->num; ++id)
  339. {
  340. virtio_console_dev->info[id].tx_ctrl_paddr = VIRTIO_VA2PA(&virtio_console_dev->info[id].tx_ctrl);
  341. }
  342. queue_ctrl_rx->avail->flags = 0;
  343. queue_ctrl_rx->avail->idx = queue_ctrl_rx->num;
  344. queue_ctrl_rx->used_idx = queue_ctrl_rx->used->idx;
  345. queue_ctrl_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
  346. queue_ctrl_tx->avail->idx = 0;
  347. virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX);
  348. }
  349. return virtio_console_port_create(virtio_console_dev, &virtio_console_port_ops);
  350. }
  351. static rt_err_t virtio_console_control(rt_device_t dev, int cmd, void *args)
  352. {
  353. rt_err_t status = RT_EOK;
  354. struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
  355. switch (cmd)
  356. {
  357. case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE:
  358. status = virtio_console_port_create(virtio_console_dev, &virtio_console_port_ops);
  359. break;
  360. default:
  361. status = -RT_EINVAL;
  362. break;
  363. }
  364. return status;
  365. }
  366. const static struct rt_device_ops virtio_console_ops =
  367. {
  368. virtio_console_init,
  369. RT_NULL,
  370. RT_NULL,
  371. RT_NULL,
  372. RT_NULL,
  373. virtio_console_control
  374. };
  375. static void virtio_console_isr(int irqno, void *param)
  376. {
  377. rt_uint32_t id;
  378. rt_uint32_t len;
  379. struct port_device *port_dev;
  380. struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)param;
  381. struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
  382. const char *dev_name = virtio_console_dev->parent.parent.name;
  383. #ifdef RT_USING_SMP
  384. rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  385. #endif
  386. virtio_interrupt_ack(virtio_dev);
  387. rt_hw_dsb();
  388. do {
  389. struct virtq *queue_rx;
  390. struct virtio_console_control *ctrl, set_ctrl;
  391. if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  392. {
  393. break;
  394. }
  395. queue_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
  396. if (queue_rx->used_idx == queue_rx->used->idx)
  397. {
  398. break;
  399. }
  400. rt_hw_dsb();
  401. id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
  402. len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
  403. queue_rx->used_idx++;
  404. if (len != sizeof(struct virtio_console_control))
  405. {
  406. rt_kprintf("%s: Invalid ctrl!\n", dev_name);
  407. break;
  408. }
  409. ctrl = &virtio_console_dev->info[id].rx_ctrl;
  410. switch (ctrl->event)
  411. {
  412. case VIRTIO_CONSOLE_PORT_ADD:
  413. {
  414. set_ctrl.id = ctrl->id;
  415. set_ctrl.event = VIRTIO_CONSOLE_PORT_READY;
  416. set_ctrl.value = 1;
  417. #ifdef RT_USING_SMP
  418. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  419. #endif
  420. virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
  421. #ifdef RT_USING_SMP
  422. level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  423. #endif
  424. }
  425. break;
  426. case VIRTIO_CONSOLE_PORT_REMOVE:
  427. break;
  428. case VIRTIO_CONSOLE_RESIZE:
  429. break;
  430. case VIRTIO_CONSOLE_PORT_OPEN:
  431. {
  432. set_ctrl.id = ctrl->id;
  433. set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
  434. set_ctrl.value = 1;
  435. #ifdef RT_USING_SMP
  436. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  437. #endif
  438. virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
  439. #ifdef RT_USING_SMP
  440. level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
  441. #endif
  442. }
  443. break;
  444. case VIRTIO_CONSOLE_PORT_NAME:
  445. break;
  446. default:
  447. rt_kprintf("%s: Unsupport ctrl[id: %d, event: %d, value: %d]!\n",
  448. dev_name, ctrl->id, ctrl->event, ctrl->value);
  449. break;
  450. }
  451. } while (0);
  452. #ifdef RT_USING_SMP
  453. rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
  454. #endif
  455. rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
  456. {
  457. rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
  458. struct virtq *queue_rx = port_dev->queue_rx;
  459. #ifdef RT_USING_SMP
  460. rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
  461. #endif
  462. if (queue_rx->used_idx != queue_rx->used->idx)
  463. {
  464. rt_hw_dsb();
  465. id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
  466. len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
  467. if (port_dev->parent.rx_indicate != RT_NULL && port_dev->rx_notify)
  468. {
  469. #ifdef RT_USING_SMP
  470. rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
  471. #endif
  472. /* rx_indicate call virtio_console_port_read to inc used_idx */
  473. port_dev->parent.rx_indicate(&port_dev->parent, len);
  474. #ifdef RT_USING_SMP
  475. level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
  476. #endif
  477. }
  478. else
  479. {
  480. queue_rx->used_idx++;
  481. virtio_submit_chain(virtio_dev, queue_rx_index, id);
  482. virtio_queue_notify(virtio_dev, queue_rx_index);
  483. }
  484. }
  485. #ifdef RT_USING_SMP
  486. rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
  487. #endif
  488. }
  489. }
  490. rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
  491. {
  492. int i;
  493. rt_size_t queues_num;
  494. static int dev_no = 0;
  495. char dev_name[RT_NAME_MAX];
  496. struct virtio_device *virtio_dev;
  497. struct virtio_console_device *virtio_console_dev;
  498. RT_ASSERT(RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR > 0);
  499. virtio_console_dev = rt_malloc(sizeof(struct virtio_console_device));
  500. if (virtio_console_dev == RT_NULL)
  501. {
  502. goto _alloc_fail;
  503. }
  504. virtio_dev = &virtio_console_dev->virtio_dev;
  505. virtio_dev->irq = irq;
  506. virtio_dev->mmio_base = mmio_base;
  507. virtio_console_dev->config = (struct virtio_console_config *)virtio_dev->mmio_config->config;
  508. #ifdef RT_USING_SMP
  509. rt_spin_lock_init(&virtio_dev->spinlock);
  510. #endif
  511. virtio_reset_device(virtio_dev);
  512. virtio_status_acknowledge_driver(virtio_dev);
  513. virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
  514. (1 << VIRTIO_F_RING_EVENT_IDX) |
  515. (1 << VIRTIO_F_RING_INDIRECT_DESC));
  516. virtio_status_driver_ok(virtio_dev);
  517. if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
  518. {
  519. virtio_console_dev->max_port_nr = 1;
  520. queues_num = 2;
  521. }
  522. else
  523. {
  524. if (virtio_console_dev->config->max_nr_ports > RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR)
  525. {
  526. virtio_console_dev->max_port_nr = RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR;
  527. virtio_console_dev->config->max_nr_ports = virtio_console_dev->max_port_nr;
  528. }
  529. else
  530. {
  531. virtio_console_dev->max_port_nr = virtio_console_dev->config->max_nr_ports;
  532. }
  533. queues_num = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(virtio_console_dev->max_port_nr, VIRTIO_CONSOLE_QUEUE_DATA_RX);
  534. }
  535. if (virtio_queues_alloc(virtio_dev, queues_num) != RT_EOK)
  536. {
  537. goto _alloc_fail;
  538. }
  539. for (i = 0; i < virtio_dev->queues_num; ++i)
  540. {
  541. if (virtio_queue_init(virtio_dev, i, VIRTIO_CONSOLE_QUEUE_SIZE) != RT_EOK)
  542. {
  543. for (; i >= 0; --i)
  544. {
  545. virtio_queue_destroy(virtio_dev, i);
  546. }
  547. goto _alloc_fail;
  548. }
  549. }
  550. virtio_console_dev->parent.type = RT_Device_Class_Char;
  551. virtio_console_dev->parent.ops = &virtio_console_ops;
  552. virtio_console_dev->parent.rx_indicate = RT_NULL;
  553. virtio_console_dev->parent.tx_complete = RT_NULL;
  554. virtio_console_dev->console_id = dev_no;
  555. virtio_console_dev->port_nr = 0;
  556. rt_list_init(&virtio_console_dev->port_head);
  557. rt_snprintf(dev_name, RT_NAME_MAX, "virtio-console%d", dev_no++);
  558. rt_hw_interrupt_install(irq, virtio_console_isr, virtio_console_dev, dev_name);
  559. rt_hw_interrupt_umask(irq);
  560. return rt_device_register((rt_device_t)virtio_console_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
  561. _alloc_fail:
  562. if (virtio_console_dev != RT_NULL)
  563. {
  564. virtio_queues_free(virtio_dev);
  565. rt_free(virtio_console_dev);
  566. }
  567. return -RT_ENOMEM;
  568. }
  569. #endif /* RT_USING_VIRTIO_CONSOLE */