bcm_vk_tty.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2018-2020 Broadcom.
  4. */
  5. #include <linux/tty.h>
  6. #include <linux/tty_driver.h>
  7. #include <linux/tty_flip.h>
  8. #include "bcm_vk.h"
  9. /* TTYVK base offset is 0x30000 into BAR1 */
  10. #define BAR1_TTYVK_BASE_OFFSET 0x300000
  11. /* Each TTYVK channel (TO or FROM) is 0x10000 */
  12. #define BAR1_TTYVK_CHAN_OFFSET 0x100000
  13. /* Each TTYVK channel has TO and FROM, hence the * 2 */
  14. #define BAR1_TTYVK_BASE(index) (BAR1_TTYVK_BASE_OFFSET + \
  15. ((index) * BAR1_TTYVK_CHAN_OFFSET * 2))
  16. /* TO TTYVK channel base comes before FROM for each index */
  17. #define TO_TTYK_BASE(index) BAR1_TTYVK_BASE(index)
  18. #define FROM_TTYK_BASE(index) (BAR1_TTYVK_BASE(index) + \
  19. BAR1_TTYVK_CHAN_OFFSET)
  20. struct bcm_vk_tty_chan {
  21. u32 reserved;
  22. u32 size;
  23. u32 wr;
  24. u32 rd;
  25. u32 *data;
  26. };
  27. #define VK_BAR_CHAN(v, DIR, e) ((v)->DIR##_offset \
  28. + offsetof(struct bcm_vk_tty_chan, e))
  29. #define VK_BAR_CHAN_SIZE(v, DIR) VK_BAR_CHAN(v, DIR, size)
  30. #define VK_BAR_CHAN_WR(v, DIR) VK_BAR_CHAN(v, DIR, wr)
  31. #define VK_BAR_CHAN_RD(v, DIR) VK_BAR_CHAN(v, DIR, rd)
  32. #define VK_BAR_CHAN_DATA(v, DIR, off) (VK_BAR_CHAN(v, DIR, data) + (off))
  33. #define VK_BAR0_REGSEG_TTY_DB_OFFSET 0x86c
  34. /* Poll every 1/10 of second - temp hack till we use MSI interrupt */
  35. #define SERIAL_TIMER_VALUE (HZ / 10)
  36. static void bcm_vk_tty_poll(struct timer_list *t)
  37. {
  38. struct bcm_vk *vk = from_timer(vk, t, serial_timer);
  39. queue_work(vk->tty_wq_thread, &vk->tty_wq_work);
  40. mod_timer(&vk->serial_timer, jiffies + SERIAL_TIMER_VALUE);
  41. }
  42. irqreturn_t bcm_vk_tty_irqhandler(int irq, void *dev_id)
  43. {
  44. struct bcm_vk *vk = dev_id;
  45. queue_work(vk->tty_wq_thread, &vk->tty_wq_work);
  46. return IRQ_HANDLED;
  47. }
  48. static void bcm_vk_tty_wq_handler(struct work_struct *work)
  49. {
  50. struct bcm_vk *vk = container_of(work, struct bcm_vk, tty_wq_work);
  51. struct bcm_vk_tty *vktty;
  52. int card_status;
  53. int count;
  54. unsigned char c;
  55. int i;
  56. int wr;
  57. card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS);
  58. if (BCM_VK_INTF_IS_DOWN(card_status))
  59. return;
  60. for (i = 0; i < BCM_VK_NUM_TTY; i++) {
  61. count = 0;
  62. /* Check the card status that the tty channel is ready */
  63. if ((card_status & BIT(i)) == 0)
  64. continue;
  65. vktty = &vk->tty[i];
  66. /* Don't increment read index if tty app is closed */
  67. if (!vktty->is_opened)
  68. continue;
  69. /* Fetch the wr offset in buffer from VK */
  70. wr = vkread32(vk, BAR_1, VK_BAR_CHAN_WR(vktty, from));
  71. /* safe to ignore until bar read gives proper size */
  72. if (vktty->from_size == 0)
  73. continue;
  74. if (wr >= vktty->from_size) {
  75. dev_err(&vk->pdev->dev,
  76. "ERROR: wq handler ttyVK%d wr:0x%x > 0x%x\n",
  77. i, wr, vktty->from_size);
  78. /* Need to signal and close device in this case */
  79. continue;
  80. }
  81. /*
  82. * Simple read of circular buffer and
  83. * insert into tty flip buffer
  84. */
  85. while (vk->tty[i].rd != wr) {
  86. c = vkread8(vk, BAR_1,
  87. VK_BAR_CHAN_DATA(vktty, from, vktty->rd));
  88. vktty->rd++;
  89. if (vktty->rd >= vktty->from_size)
  90. vktty->rd = 0;
  91. tty_insert_flip_char(&vktty->port, c, TTY_NORMAL);
  92. count++;
  93. }
  94. if (count) {
  95. tty_flip_buffer_push(&vktty->port);
  96. /* Update read offset from shadow register to card */
  97. vkwrite32(vk, vktty->rd, BAR_1,
  98. VK_BAR_CHAN_RD(vktty, from));
  99. }
  100. }
  101. }
  102. static int bcm_vk_tty_open(struct tty_struct *tty, struct file *file)
  103. {
  104. int card_status;
  105. struct bcm_vk *vk;
  106. struct bcm_vk_tty *vktty;
  107. int index;
  108. /* initialize the pointer in case something fails */
  109. tty->driver_data = NULL;
  110. vk = (struct bcm_vk *)dev_get_drvdata(tty->dev);
  111. index = tty->index;
  112. if (index >= BCM_VK_NUM_TTY)
  113. return -EINVAL;
  114. vktty = &vk->tty[index];
  115. vktty->pid = task_pid_nr(current);
  116. vktty->to_offset = TO_TTYK_BASE(index);
  117. vktty->from_offset = FROM_TTYK_BASE(index);
  118. /* Do not allow tty device to be opened if tty on card not ready */
  119. card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS);
  120. if (BCM_VK_INTF_IS_DOWN(card_status) || ((card_status & BIT(index)) == 0))
  121. return -EBUSY;
  122. /*
  123. * Get shadow registers of the buffer sizes and the "to" write offset
  124. * and "from" read offset
  125. */
  126. vktty->to_size = vkread32(vk, BAR_1, VK_BAR_CHAN_SIZE(vktty, to));
  127. vktty->wr = vkread32(vk, BAR_1, VK_BAR_CHAN_WR(vktty, to));
  128. vktty->from_size = vkread32(vk, BAR_1, VK_BAR_CHAN_SIZE(vktty, from));
  129. vktty->rd = vkread32(vk, BAR_1, VK_BAR_CHAN_RD(vktty, from));
  130. vktty->is_opened = true;
  131. if (tty->count == 1 && !vktty->irq_enabled) {
  132. timer_setup(&vk->serial_timer, bcm_vk_tty_poll, 0);
  133. mod_timer(&vk->serial_timer, jiffies + SERIAL_TIMER_VALUE);
  134. }
  135. return 0;
  136. }
  137. static void bcm_vk_tty_close(struct tty_struct *tty, struct file *file)
  138. {
  139. struct bcm_vk *vk = dev_get_drvdata(tty->dev);
  140. if (tty->index >= BCM_VK_NUM_TTY)
  141. return;
  142. vk->tty[tty->index].is_opened = false;
  143. if (tty->count == 1)
  144. del_timer_sync(&vk->serial_timer);
  145. }
  146. static void bcm_vk_tty_doorbell(struct bcm_vk *vk, u32 db_val)
  147. {
  148. vkwrite32(vk, db_val, BAR_0,
  149. VK_BAR0_REGSEG_DB_BASE + VK_BAR0_REGSEG_TTY_DB_OFFSET);
  150. }
  151. static int bcm_vk_tty_write(struct tty_struct *tty,
  152. const unsigned char *buffer,
  153. int count)
  154. {
  155. int index;
  156. struct bcm_vk *vk;
  157. struct bcm_vk_tty *vktty;
  158. int i;
  159. index = tty->index;
  160. vk = dev_get_drvdata(tty->dev);
  161. vktty = &vk->tty[index];
  162. /* Simple write each byte to circular buffer */
  163. for (i = 0; i < count; i++) {
  164. vkwrite8(vk, buffer[i], BAR_1,
  165. VK_BAR_CHAN_DATA(vktty, to, vktty->wr));
  166. vktty->wr++;
  167. if (vktty->wr >= vktty->to_size)
  168. vktty->wr = 0;
  169. }
  170. /* Update write offset from shadow register to card */
  171. vkwrite32(vk, vktty->wr, BAR_1, VK_BAR_CHAN_WR(vktty, to));
  172. bcm_vk_tty_doorbell(vk, 0);
  173. return count;
  174. }
  175. static unsigned int bcm_vk_tty_write_room(struct tty_struct *tty)
  176. {
  177. struct bcm_vk *vk = dev_get_drvdata(tty->dev);
  178. return vk->tty[tty->index].to_size - 1;
  179. }
  180. static const struct tty_operations serial_ops = {
  181. .open = bcm_vk_tty_open,
  182. .close = bcm_vk_tty_close,
  183. .write = bcm_vk_tty_write,
  184. .write_room = bcm_vk_tty_write_room,
  185. };
  186. int bcm_vk_tty_init(struct bcm_vk *vk, char *name)
  187. {
  188. int i;
  189. int err;
  190. struct tty_driver *tty_drv;
  191. struct device *dev = &vk->pdev->dev;
  192. tty_drv = tty_alloc_driver
  193. (BCM_VK_NUM_TTY,
  194. TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
  195. if (IS_ERR(tty_drv))
  196. return PTR_ERR(tty_drv);
  197. /* Save struct tty_driver for uninstalling the device */
  198. vk->tty_drv = tty_drv;
  199. /* initialize the tty driver */
  200. tty_drv->driver_name = KBUILD_MODNAME;
  201. tty_drv->name = kstrdup(name, GFP_KERNEL);
  202. if (!tty_drv->name) {
  203. err = -ENOMEM;
  204. goto err_tty_driver_kref_put;
  205. }
  206. tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
  207. tty_drv->subtype = SERIAL_TYPE_NORMAL;
  208. tty_drv->init_termios = tty_std_termios;
  209. tty_set_operations(tty_drv, &serial_ops);
  210. /* register the tty driver */
  211. err = tty_register_driver(tty_drv);
  212. if (err) {
  213. dev_err(dev, "tty_register_driver failed\n");
  214. goto err_kfree_tty_name;
  215. }
  216. for (i = 0; i < BCM_VK_NUM_TTY; i++) {
  217. struct device *tty_dev;
  218. tty_port_init(&vk->tty[i].port);
  219. tty_dev = tty_port_register_device_attr(&vk->tty[i].port,
  220. tty_drv, i, dev, vk,
  221. NULL);
  222. if (IS_ERR(tty_dev)) {
  223. err = PTR_ERR(tty_dev);
  224. goto unwind;
  225. }
  226. vk->tty[i].is_opened = false;
  227. }
  228. INIT_WORK(&vk->tty_wq_work, bcm_vk_tty_wq_handler);
  229. vk->tty_wq_thread = create_singlethread_workqueue("tty");
  230. if (!vk->tty_wq_thread) {
  231. dev_err(dev, "Fail to create tty workqueue thread\n");
  232. err = -ENOMEM;
  233. goto unwind;
  234. }
  235. return 0;
  236. unwind:
  237. while (--i >= 0)
  238. tty_port_unregister_device(&vk->tty[i].port, tty_drv, i);
  239. tty_unregister_driver(tty_drv);
  240. err_kfree_tty_name:
  241. kfree(tty_drv->name);
  242. tty_drv->name = NULL;
  243. err_tty_driver_kref_put:
  244. tty_driver_kref_put(tty_drv);
  245. return err;
  246. }
  247. void bcm_vk_tty_exit(struct bcm_vk *vk)
  248. {
  249. int i;
  250. del_timer_sync(&vk->serial_timer);
  251. for (i = 0; i < BCM_VK_NUM_TTY; ++i) {
  252. tty_port_unregister_device(&vk->tty[i].port,
  253. vk->tty_drv,
  254. i);
  255. tty_port_destroy(&vk->tty[i].port);
  256. }
  257. tty_unregister_driver(vk->tty_drv);
  258. kfree(vk->tty_drv->name);
  259. vk->tty_drv->name = NULL;
  260. tty_driver_kref_put(vk->tty_drv);
  261. }
  262. void bcm_vk_tty_terminate_tty_user(struct bcm_vk *vk)
  263. {
  264. struct bcm_vk_tty *vktty;
  265. int i;
  266. for (i = 0; i < BCM_VK_NUM_TTY; ++i) {
  267. vktty = &vk->tty[i];
  268. if (vktty->pid)
  269. kill_pid(find_vpid(vktty->pid), SIGKILL, 1);
  270. }
  271. }
  272. void bcm_vk_tty_wq_exit(struct bcm_vk *vk)
  273. {
  274. cancel_work_sync(&vk->tty_wq_work);
  275. destroy_workqueue(vk->tty_wq_thread);
  276. }