vpe-mt.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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) 2004, 2005 MIPS Technologies, Inc. All rights reserved.
  7. * Copyright (C) 2013 Imagination Technologies Ltd.
  8. */
  9. #include <linux/kernel.h>
  10. #include <linux/device.h>
  11. #include <linux/fs.h>
  12. #include <linux/slab.h>
  13. #include <linux/export.h>
  14. #include <asm/mipsregs.h>
  15. #include <asm/mipsmtregs.h>
  16. #include <asm/mips_mt.h>
  17. #include <asm/vpe.h>
  18. static int major;
  19. /* The number of TCs and VPEs physically available on the core */
  20. static int hw_tcs, hw_vpes;
  21. /* We are prepared so configure and start the VPE... */
  22. int vpe_run(struct vpe *v)
  23. {
  24. unsigned long flags, val, dmt_flag;
  25. struct vpe_notifications *notifier;
  26. unsigned int vpeflags;
  27. struct tc *t;
  28. /* check we are the Master VPE */
  29. local_irq_save(flags);
  30. val = read_c0_vpeconf0();
  31. if (!(val & VPECONF0_MVP)) {
  32. pr_warn("VPE loader: only Master VPE's are able to config MT\n");
  33. local_irq_restore(flags);
  34. return -1;
  35. }
  36. dmt_flag = dmt();
  37. vpeflags = dvpe();
  38. if (list_empty(&v->tc)) {
  39. evpe(vpeflags);
  40. emt(dmt_flag);
  41. local_irq_restore(flags);
  42. pr_warn("VPE loader: No TC's associated with VPE %d\n",
  43. v->minor);
  44. return -ENOEXEC;
  45. }
  46. t = list_first_entry(&v->tc, struct tc, tc);
  47. /* Put MVPE's into 'configuration state' */
  48. set_c0_mvpcontrol(MVPCONTROL_VPC);
  49. settc(t->index);
  50. /* should check it is halted, and not activated */
  51. if ((read_tc_c0_tcstatus() & TCSTATUS_A) ||
  52. !(read_tc_c0_tchalt() & TCHALT_H)) {
  53. evpe(vpeflags);
  54. emt(dmt_flag);
  55. local_irq_restore(flags);
  56. pr_warn("VPE loader: TC %d is already active!\n",
  57. t->index);
  58. return -ENOEXEC;
  59. }
  60. /*
  61. * Write the address we want it to start running from in the TCPC
  62. * register.
  63. */
  64. write_tc_c0_tcrestart((unsigned long)v->__start);
  65. write_tc_c0_tccontext((unsigned long)0);
  66. /*
  67. * Mark the TC as activated, not interrupt exempt and not dynamically
  68. * allocatable
  69. */
  70. val = read_tc_c0_tcstatus();
  71. val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
  72. write_tc_c0_tcstatus(val);
  73. write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
  74. /*
  75. * We don't pass the memsize here, so VPE programs need to be
  76. * compiled with DFLT_STACK_SIZE and DFLT_HEAP_SIZE defined.
  77. */
  78. mttgpr($7, 0);
  79. mttgpr($6, v->ntcs);
  80. /* set up VPE1 */
  81. /*
  82. * bind the TC to VPE 1 as late as possible so we only have the final
  83. * VPE registers to set up, and so an EJTAG probe can trigger on it
  84. */
  85. write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
  86. write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
  87. back_to_back_c0_hazard();
  88. /* Set up the XTC bit in vpeconf0 to point at our tc */
  89. write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
  90. | (t->index << VPECONF0_XTC_SHIFT));
  91. back_to_back_c0_hazard();
  92. /* enable this VPE */
  93. write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
  94. /* clear out any left overs from a previous program */
  95. write_vpe_c0_status(0);
  96. write_vpe_c0_cause(0);
  97. /* take system out of configuration state */
  98. clear_c0_mvpcontrol(MVPCONTROL_VPC);
  99. /*
  100. * SMVP kernels manage VPE enable independently, but uniprocessor
  101. * kernels need to turn it on, even if that wasn't the pre-dvpe() state.
  102. */
  103. #ifdef CONFIG_SMP
  104. evpe(vpeflags);
  105. #else
  106. evpe(EVPE_ENABLE);
  107. #endif
  108. emt(dmt_flag);
  109. local_irq_restore(flags);
  110. list_for_each_entry(notifier, &v->notify, list)
  111. notifier->start(VPE_MODULE_MINOR);
  112. return 0;
  113. }
  114. void cleanup_tc(struct tc *tc)
  115. {
  116. unsigned long flags;
  117. unsigned int mtflags, vpflags;
  118. int tmp;
  119. local_irq_save(flags);
  120. mtflags = dmt();
  121. vpflags = dvpe();
  122. /* Put MVPE's into 'configuration state' */
  123. set_c0_mvpcontrol(MVPCONTROL_VPC);
  124. settc(tc->index);
  125. tmp = read_tc_c0_tcstatus();
  126. /* mark not allocated and not dynamically allocatable */
  127. tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
  128. tmp |= TCSTATUS_IXMT; /* interrupt exempt */
  129. write_tc_c0_tcstatus(tmp);
  130. write_tc_c0_tchalt(TCHALT_H);
  131. mips_ihb();
  132. clear_c0_mvpcontrol(MVPCONTROL_VPC);
  133. evpe(vpflags);
  134. emt(mtflags);
  135. local_irq_restore(flags);
  136. }
  137. /* module wrapper entry points */
  138. /* give me a vpe */
  139. void *vpe_alloc(void)
  140. {
  141. int i;
  142. struct vpe *v;
  143. /* find a vpe */
  144. for (i = 1; i < MAX_VPES; i++) {
  145. v = get_vpe(i);
  146. if (v != NULL) {
  147. v->state = VPE_STATE_INUSE;
  148. return v;
  149. }
  150. }
  151. return NULL;
  152. }
  153. EXPORT_SYMBOL(vpe_alloc);
  154. /* start running from here */
  155. int vpe_start(void *vpe, unsigned long start)
  156. {
  157. struct vpe *v = vpe;
  158. v->__start = start;
  159. return vpe_run(v);
  160. }
  161. EXPORT_SYMBOL(vpe_start);
  162. /* halt it for now */
  163. int vpe_stop(void *vpe)
  164. {
  165. struct vpe *v = vpe;
  166. struct tc *t;
  167. unsigned int evpe_flags;
  168. evpe_flags = dvpe();
  169. t = list_entry(v->tc.next, struct tc, tc);
  170. if (t != NULL) {
  171. settc(t->index);
  172. write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
  173. }
  174. evpe(evpe_flags);
  175. return 0;
  176. }
  177. EXPORT_SYMBOL(vpe_stop);
  178. /* I've done with it thank you */
  179. int vpe_free(void *vpe)
  180. {
  181. struct vpe *v = vpe;
  182. struct tc *t;
  183. unsigned int evpe_flags;
  184. t = list_entry(v->tc.next, struct tc, tc);
  185. if (t == NULL)
  186. return -ENOEXEC;
  187. evpe_flags = dvpe();
  188. /* Put MVPE's into 'configuration state' */
  189. set_c0_mvpcontrol(MVPCONTROL_VPC);
  190. settc(t->index);
  191. write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
  192. /* halt the TC */
  193. write_tc_c0_tchalt(TCHALT_H);
  194. mips_ihb();
  195. /* mark the TC unallocated */
  196. write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
  197. v->state = VPE_STATE_UNUSED;
  198. clear_c0_mvpcontrol(MVPCONTROL_VPC);
  199. evpe(evpe_flags);
  200. return 0;
  201. }
  202. EXPORT_SYMBOL(vpe_free);
  203. static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
  204. const char *buf, size_t len)
  205. {
  206. struct vpe *vpe = get_vpe(aprp_cpu_index());
  207. struct vpe_notifications *notifier;
  208. list_for_each_entry(notifier, &vpe->notify, list)
  209. notifier->stop(aprp_cpu_index());
  210. release_progmem(vpe->load_addr);
  211. cleanup_tc(get_tc(aprp_cpu_index()));
  212. vpe_stop(vpe);
  213. vpe_free(vpe);
  214. return len;
  215. }
  216. static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill);
  217. static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr,
  218. char *buf)
  219. {
  220. struct vpe *vpe = get_vpe(aprp_cpu_index());
  221. return sprintf(buf, "%d\n", vpe->ntcs);
  222. }
  223. static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr,
  224. const char *buf, size_t len)
  225. {
  226. struct vpe *vpe = get_vpe(aprp_cpu_index());
  227. unsigned long new;
  228. int ret;
  229. ret = kstrtoul(buf, 0, &new);
  230. if (ret < 0)
  231. return ret;
  232. if (new == 0 || new > (hw_tcs - aprp_cpu_index()))
  233. return -EINVAL;
  234. vpe->ntcs = new;
  235. return len;
  236. }
  237. static DEVICE_ATTR_RW(ntcs);
  238. static struct attribute *vpe_attrs[] = {
  239. &dev_attr_kill.attr,
  240. &dev_attr_ntcs.attr,
  241. NULL,
  242. };
  243. ATTRIBUTE_GROUPS(vpe);
  244. static void vpe_device_release(struct device *cd)
  245. {
  246. }
  247. static struct class vpe_class = {
  248. .name = "vpe",
  249. .dev_release = vpe_device_release,
  250. .dev_groups = vpe_groups,
  251. };
  252. static struct device vpe_device;
  253. int __init vpe_module_init(void)
  254. {
  255. unsigned int mtflags, vpflags;
  256. unsigned long flags, val;
  257. struct vpe *v = NULL;
  258. struct tc *t;
  259. int tc, err;
  260. if (!cpu_has_mipsmt) {
  261. pr_warn("VPE loader: not a MIPS MT capable processor\n");
  262. return -ENODEV;
  263. }
  264. if (vpelimit == 0) {
  265. pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n"
  266. "Pass maxvpes=<n> argument as kernel argument\n");
  267. return -ENODEV;
  268. }
  269. if (aprp_cpu_index() == 0) {
  270. pr_warn("No TCs reserved for AP/SP, not initialize VPE loader\n"
  271. "Pass maxtcs=<n> argument as kernel argument\n");
  272. return -ENODEV;
  273. }
  274. major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops);
  275. if (major < 0) {
  276. pr_warn("VPE loader: unable to register character device\n");
  277. return major;
  278. }
  279. err = class_register(&vpe_class);
  280. if (err) {
  281. pr_err("vpe_class registration failed\n");
  282. goto out_chrdev;
  283. }
  284. device_initialize(&vpe_device);
  285. vpe_device.class = &vpe_class;
  286. vpe_device.parent = NULL;
  287. dev_set_name(&vpe_device, "vpe1");
  288. vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR);
  289. err = device_add(&vpe_device);
  290. if (err) {
  291. pr_err("Adding vpe_device failed\n");
  292. goto out_class;
  293. }
  294. local_irq_save(flags);
  295. mtflags = dmt();
  296. vpflags = dvpe();
  297. /* Put MVPE's into 'configuration state' */
  298. set_c0_mvpcontrol(MVPCONTROL_VPC);
  299. val = read_c0_mvpconf0();
  300. hw_tcs = (val & MVPCONF0_PTC) + 1;
  301. hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
  302. for (tc = aprp_cpu_index(); tc < hw_tcs; tc++) {
  303. /*
  304. * Must re-enable multithreading temporarily or in case we
  305. * reschedule send IPIs or similar we might hang.
  306. */
  307. clear_c0_mvpcontrol(MVPCONTROL_VPC);
  308. evpe(vpflags);
  309. emt(mtflags);
  310. local_irq_restore(flags);
  311. t = alloc_tc(tc);
  312. if (!t) {
  313. err = -ENOMEM;
  314. goto out_dev;
  315. }
  316. local_irq_save(flags);
  317. mtflags = dmt();
  318. vpflags = dvpe();
  319. set_c0_mvpcontrol(MVPCONTROL_VPC);
  320. /* VPE's */
  321. if (tc < hw_tcs) {
  322. settc(tc);
  323. v = alloc_vpe(tc);
  324. if (v == NULL) {
  325. pr_warn("VPE: unable to allocate VPE\n");
  326. goto out_reenable;
  327. }
  328. v->ntcs = hw_tcs - aprp_cpu_index();
  329. /* add the tc to the list of this vpe's tc's. */
  330. list_add(&t->tc, &v->tc);
  331. /* deactivate all but vpe0 */
  332. if (tc >= aprp_cpu_index()) {
  333. unsigned long tmp = read_vpe_c0_vpeconf0();
  334. tmp &= ~VPECONF0_VPA;
  335. /* master VPE */
  336. tmp |= VPECONF0_MVP;
  337. write_vpe_c0_vpeconf0(tmp);
  338. }
  339. /* disable multi-threading with TC's */
  340. write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() &
  341. ~VPECONTROL_TE);
  342. if (tc >= vpelimit) {
  343. /*
  344. * Set config to be the same as vpe0,
  345. * particularly kseg0 coherency alg
  346. */
  347. write_vpe_c0_config(read_c0_config());
  348. }
  349. }
  350. /* TC's */
  351. t->pvpe = v; /* set the parent vpe */
  352. if (tc >= aprp_cpu_index()) {
  353. unsigned long tmp;
  354. settc(tc);
  355. /*
  356. * A TC that is bound to any other VPE gets bound to
  357. * VPE0, ideally I'd like to make it homeless but it
  358. * doesn't appear to let me bind a TC to a non-existent
  359. * VPE. Which is perfectly reasonable.
  360. *
  361. * The (un)bound state is visible to an EJTAG probe so
  362. * may notify GDB...
  363. */
  364. tmp = read_tc_c0_tcbind();
  365. if (tmp & TCBIND_CURVPE) {
  366. /* tc is bound >vpe0 */
  367. write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
  368. t->pvpe = get_vpe(0); /* set the parent vpe */
  369. }
  370. /* halt the TC */
  371. write_tc_c0_tchalt(TCHALT_H);
  372. mips_ihb();
  373. tmp = read_tc_c0_tcstatus();
  374. /* mark not activated and not dynamically allocatable */
  375. tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
  376. tmp |= TCSTATUS_IXMT; /* interrupt exempt */
  377. write_tc_c0_tcstatus(tmp);
  378. }
  379. }
  380. out_reenable:
  381. /* release config state */
  382. clear_c0_mvpcontrol(MVPCONTROL_VPC);
  383. evpe(vpflags);
  384. emt(mtflags);
  385. local_irq_restore(flags);
  386. return 0;
  387. out_dev:
  388. device_del(&vpe_device);
  389. out_class:
  390. put_device(&vpe_device);
  391. class_unregister(&vpe_class);
  392. out_chrdev:
  393. unregister_chrdev(major, VPE_MODULE_NAME);
  394. return err;
  395. }
  396. void __exit vpe_module_exit(void)
  397. {
  398. struct vpe *v, *n;
  399. device_unregister(&vpe_device);
  400. class_unregister(&vpe_class);
  401. unregister_chrdev(major, VPE_MODULE_NAME);
  402. /* No locking needed here */
  403. list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
  404. if (v->state != VPE_STATE_UNUSED)
  405. release_vpe(v);
  406. }
  407. }