rtlx.c 8.7 KB

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