rtlx.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved.
  7. * Copyright (C) 2005, 06 Ralf Baechle ([email protected])
  8. * Copyright (C) 2013 Imagination Technologies Ltd.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/fs.h>
  12. #include <linux/syscalls.h>
  13. #include <linux/moduleloader.h>
  14. #include <linux/atomic.h>
  15. #include <linux/sched/signal.h>
  16. #include <asm/mipsmtregs.h>
  17. #include <asm/mips_mt.h>
  18. #include <asm/processor.h>
  19. #include <asm/rtlx.h>
  20. #include <asm/setup.h>
  21. #include <asm/vpe.h>
  22. static int sp_stopping;
  23. struct rtlx_info *rtlx;
  24. struct chan_waitqueues channel_wqs[RTLX_CHANNELS];
  25. struct vpe_notifications rtlx_notify;
  26. void (*aprp_hook)(void) = NULL;
  27. EXPORT_SYMBOL(aprp_hook);
  28. static void __used dump_rtlx(void)
  29. {
  30. int i;
  31. pr_info("id 0x%lx state %d\n", rtlx->id, rtlx->state);
  32. for (i = 0; i < RTLX_CHANNELS; i++) {
  33. struct rtlx_channel *chan = &rtlx->channel[i];
  34. pr_info(" rt_state %d lx_state %d buffer_size %d\n",
  35. chan->rt_state, chan->lx_state, chan->buffer_size);
  36. pr_info(" rt_read %d rt_write %d\n",
  37. chan->rt_read, chan->rt_write);
  38. pr_info(" lx_read %d lx_write %d\n",
  39. chan->lx_read, chan->lx_write);
  40. pr_info(" rt_buffer <%s>\n", chan->rt_buffer);
  41. pr_info(" lx_buffer <%s>\n", chan->lx_buffer);
  42. }
  43. }
  44. /* call when we have the address of the shared structure from the SP side. */
  45. static int rtlx_init(struct rtlx_info *rtlxi)
  46. {
  47. if (rtlxi->id != RTLX_ID) {
  48. pr_err("no valid RTLX id at 0x%p 0x%lx\n", rtlxi, rtlxi->id);
  49. return -ENOEXEC;
  50. }
  51. rtlx = rtlxi;
  52. return 0;
  53. }
  54. /* notifications */
  55. void rtlx_starting(int vpe)
  56. {
  57. int i;
  58. sp_stopping = 0;
  59. /* force a reload of rtlx */
  60. rtlx = NULL;
  61. /* wake up any sleeping rtlx_open's */
  62. for (i = 0; i < RTLX_CHANNELS; i++)
  63. wake_up_interruptible(&channel_wqs[i].lx_queue);
  64. }
  65. void rtlx_stopping(int vpe)
  66. {
  67. int i;
  68. sp_stopping = 1;
  69. for (i = 0; i < RTLX_CHANNELS; i++)
  70. wake_up_interruptible(&channel_wqs[i].lx_queue);
  71. }
  72. int rtlx_open(int index, int can_sleep)
  73. {
  74. struct rtlx_info **p;
  75. struct rtlx_channel *chan;
  76. enum rtlx_state state;
  77. int ret = 0;
  78. if (index >= RTLX_CHANNELS) {
  79. pr_debug("rtlx_open index out of range\n");
  80. return -ENOSYS;
  81. }
  82. if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
  83. pr_debug("rtlx_open channel %d already opened\n", index);
  84. ret = -EBUSY;
  85. goto out_fail;
  86. }
  87. if (rtlx == NULL) {
  88. p = vpe_get_shared(aprp_cpu_index());
  89. if (p == NULL) {
  90. if (can_sleep) {
  91. ret = __wait_event_interruptible(
  92. channel_wqs[index].lx_queue,
  93. (p = vpe_get_shared(aprp_cpu_index())));
  94. if (ret)
  95. goto out_fail;
  96. } else {
  97. pr_debug("No SP program loaded, and device opened with O_NONBLOCK\n");
  98. ret = -ENOSYS;
  99. goto out_fail;
  100. }
  101. }
  102. smp_rmb();
  103. if (*p == NULL) {
  104. if (can_sleep) {
  105. DEFINE_WAIT(wait);
  106. for (;;) {
  107. prepare_to_wait(
  108. &channel_wqs[index].lx_queue,
  109. &wait, TASK_INTERRUPTIBLE);
  110. smp_rmb();
  111. if (*p != NULL)
  112. break;
  113. if (!signal_pending(current)) {
  114. schedule();
  115. continue;
  116. }
  117. ret = -ERESTARTSYS;
  118. goto out_fail;
  119. }
  120. finish_wait(&channel_wqs[index].lx_queue,
  121. &wait);
  122. } else {
  123. pr_err(" *vpe_get_shared is NULL. Has an SP program been loaded?\n");
  124. ret = -ENOSYS;
  125. goto out_fail;
  126. }
  127. }
  128. if ((unsigned int)*p < KSEG0) {
  129. pr_warn("vpe_get_shared returned an invalid pointer maybe an error code %d\n",
  130. (int)*p);
  131. ret = -ENOSYS;
  132. goto out_fail;
  133. }
  134. ret = rtlx_init(*p);
  135. if (ret < 0)
  136. goto out_ret;
  137. }
  138. chan = &rtlx->channel[index];
  139. state = xchg(&chan->lx_state, RTLX_STATE_OPENED);
  140. if (state == RTLX_STATE_OPENED) {
  141. ret = -EBUSY;
  142. goto out_fail;
  143. }
  144. out_fail:
  145. smp_mb();
  146. atomic_dec(&channel_wqs[index].in_open);
  147. smp_mb();
  148. out_ret:
  149. return ret;
  150. }
  151. int rtlx_release(int index)
  152. {
  153. if (rtlx == NULL) {
  154. pr_err("rtlx_release() with null rtlx\n");
  155. return 0;
  156. }
  157. rtlx->channel[index].lx_state = RTLX_STATE_UNUSED;
  158. return 0;
  159. }
  160. unsigned int rtlx_read_poll(int index, int can_sleep)
  161. {
  162. struct rtlx_channel *chan;
  163. if (rtlx == NULL)
  164. return 0;
  165. chan = &rtlx->channel[index];
  166. /* data available to read? */
  167. if (chan->lx_read == chan->lx_write) {
  168. if (can_sleep) {
  169. int ret = __wait_event_interruptible(
  170. channel_wqs[index].lx_queue,
  171. (chan->lx_read != chan->lx_write) ||
  172. sp_stopping);
  173. if (ret)
  174. return ret;
  175. if (sp_stopping)
  176. return 0;
  177. } else
  178. return 0;
  179. }
  180. return (chan->lx_write + chan->buffer_size - chan->lx_read)
  181. % chan->buffer_size;
  182. }
  183. static inline int write_spacefree(int read, int write, int size)
  184. {
  185. if (read == write) {
  186. /*
  187. * Never fill the buffer completely, so indexes are always
  188. * equal if empty and only empty, or !equal if data available
  189. */
  190. return size - 1;
  191. }
  192. return ((read + size - write) % size) - 1;
  193. }
  194. unsigned int rtlx_write_poll(int index)
  195. {
  196. struct rtlx_channel *chan = &rtlx->channel[index];
  197. return write_spacefree(chan->rt_read, chan->rt_write,
  198. chan->buffer_size);
  199. }
  200. ssize_t rtlx_read(int index, void __user *buff, size_t count)
  201. {
  202. size_t lx_write, fl = 0L;
  203. struct rtlx_channel *lx;
  204. unsigned long failed;
  205. if (rtlx == NULL)
  206. return -ENOSYS;
  207. lx = &rtlx->channel[index];
  208. mutex_lock(&channel_wqs[index].mutex);
  209. smp_rmb();
  210. lx_write = lx->lx_write;
  211. /* find out how much in total */
  212. count = min(count,
  213. (size_t)(lx_write + lx->buffer_size - lx->lx_read)
  214. % lx->buffer_size);
  215. /* then how much from the read pointer onwards */
  216. fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
  217. failed = copy_to_user(buff, lx->lx_buffer + lx->lx_read, fl);
  218. if (failed)
  219. goto out;
  220. /* and if there is anything left at the beginning of the buffer */
  221. if (count - fl)
  222. failed = copy_to_user(buff + fl, lx->lx_buffer, count - fl);
  223. out:
  224. count -= failed;
  225. smp_wmb();
  226. lx->lx_read = (lx->lx_read + count) % lx->buffer_size;
  227. smp_wmb();
  228. mutex_unlock(&channel_wqs[index].mutex);
  229. return count;
  230. }
  231. ssize_t rtlx_write(int index, const void __user *buffer, size_t count)
  232. {
  233. struct rtlx_channel *rt;
  234. unsigned long failed;
  235. size_t rt_read;
  236. size_t fl;
  237. if (rtlx == NULL)
  238. return -ENOSYS;
  239. rt = &rtlx->channel[index];
  240. mutex_lock(&channel_wqs[index].mutex);
  241. smp_rmb();
  242. rt_read = rt->rt_read;
  243. /* total number of bytes to copy */
  244. count = min_t(size_t, count, write_spacefree(rt_read, rt->rt_write,
  245. rt->buffer_size));
  246. /* first bit from write pointer to the end of the buffer, or count */
  247. fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
  248. failed = copy_from_user(rt->rt_buffer + rt->rt_write, buffer, fl);
  249. if (failed)
  250. goto out;
  251. /* if there's any left copy to the beginning of the buffer */
  252. if (count - fl)
  253. failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
  254. out:
  255. count -= failed;
  256. smp_wmb();
  257. rt->rt_write = (rt->rt_write + count) % rt->buffer_size;
  258. smp_wmb();
  259. mutex_unlock(&channel_wqs[index].mutex);
  260. _interrupt_sp();
  261. return count;
  262. }
  263. static int file_open(struct inode *inode, struct file *filp)
  264. {
  265. return rtlx_open(iminor(inode), (filp->f_flags & O_NONBLOCK) ? 0 : 1);
  266. }
  267. static int file_release(struct inode *inode, struct file *filp)
  268. {
  269. return rtlx_release(iminor(inode));
  270. }
  271. static __poll_t file_poll(struct file *file, poll_table *wait)
  272. {
  273. int minor = iminor(file_inode(file));
  274. __poll_t mask = 0;
  275. poll_wait(file, &channel_wqs[minor].rt_queue, wait);
  276. poll_wait(file, &channel_wqs[minor].lx_queue, wait);
  277. if (rtlx == NULL)
  278. return 0;
  279. /* data available to read? */
  280. if (rtlx_read_poll(minor, 0))
  281. mask |= EPOLLIN | EPOLLRDNORM;
  282. /* space to write */
  283. if (rtlx_write_poll(minor))
  284. mask |= EPOLLOUT | EPOLLWRNORM;
  285. return mask;
  286. }
  287. static ssize_t file_read(struct file *file, char __user *buffer, size_t count,
  288. loff_t *ppos)
  289. {
  290. int minor = iminor(file_inode(file));
  291. /* data available? */
  292. if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1))
  293. return 0; /* -EAGAIN makes 'cat' whine */
  294. return rtlx_read(minor, buffer, count);
  295. }
  296. static ssize_t file_write(struct file *file, const char __user *buffer,
  297. size_t count, loff_t *ppos)
  298. {
  299. int minor = iminor(file_inode(file));
  300. /* any space left... */
  301. if (!rtlx_write_poll(minor)) {
  302. int ret;
  303. if (file->f_flags & O_NONBLOCK)
  304. return -EAGAIN;
  305. ret = __wait_event_interruptible(channel_wqs[minor].rt_queue,
  306. rtlx_write_poll(minor));
  307. if (ret)
  308. return ret;
  309. }
  310. return rtlx_write(minor, buffer, count);
  311. }
  312. const struct file_operations rtlx_fops = {
  313. .owner = THIS_MODULE,
  314. .open = file_open,
  315. .release = file_release,
  316. .write = file_write,
  317. .read = file_read,
  318. .poll = file_poll,
  319. .llseek = noop_llseek,
  320. };
  321. module_init(rtlx_module_init);
  322. module_exit(rtlx_module_exit);
  323. MODULE_DESCRIPTION("MIPS RTLX");
  324. MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
  325. MODULE_LICENSE("GPL");