kernel.fuc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*
  2. * Copyright 2013 Red Hat Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: Ben Skeggs
  23. */
  24. /******************************************************************************
  25. * kernel data segment
  26. *****************************************************************************/
  27. #ifdef INCLUDE_PROC
  28. proc_kern:
  29. process(PROC_KERN, 0, 0)
  30. proc_list_head:
  31. #endif
  32. #ifdef INCLUDE_DATA
  33. proc_list_tail:
  34. time_prev: .b32 0
  35. time_next: .b32 0
  36. #endif
  37. /******************************************************************************
  38. * kernel code segment
  39. *****************************************************************************/
  40. #ifdef INCLUDE_CODE
  41. bra #init
  42. // read nv register
  43. //
  44. // $r15 - current
  45. // $r14 - addr
  46. // $r13 - data (return)
  47. // $r0 - zero
  48. rd32:
  49. nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
  50. imm32($r13, NV_PPWR_MMIO_CTRL_OP_RD | NV_PPWR_MMIO_CTRL_TRIGGER)
  51. nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
  52. rd32_wait:
  53. nv_iord($r13, NV_PPWR_MMIO_CTRL)
  54. and $r13 NV_PPWR_MMIO_CTRL_STATUS
  55. bra nz #rd32_wait
  56. nv_iord($r13, NV_PPWR_MMIO_DATA)
  57. ret
  58. // write nv register
  59. //
  60. // $r15 - current
  61. // $r14 - addr
  62. // $r13 - data
  63. // $r0 - zero
  64. wr32:
  65. nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
  66. nv_iowr(NV_PPWR_MMIO_DATA, $r13)
  67. imm32($r13, NV_PPWR_MMIO_CTRL_OP_WR | NV_PPWR_MMIO_CTRL_MASK_B32_0 | NV_PPWR_MMIO_CTRL_TRIGGER)
  68. #ifdef NVKM_FALCON_MMIO_TRAP
  69. push $r13
  70. mov $r13 NV_PPWR_INTR_TRIGGER_USER1
  71. nv_iowr(NV_PPWR_INTR_TRIGGER, $r13)
  72. wr32_host:
  73. nv_iord($r13, NV_PPWR_INTR)
  74. and $r13 NV_PPWR_INTR_USER1
  75. bra nz #wr32_host
  76. pop $r13
  77. #endif
  78. nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
  79. wr32_wait:
  80. nv_iord($r13, NV_PPWR_MMIO_CTRL)
  81. and $r13 NV_PPWR_MMIO_CTRL_STATUS
  82. bra nz #wr32_wait
  83. ret
  84. // busy-wait for a period of time
  85. //
  86. // $r15 - current
  87. // $r14 - ns
  88. // $r0 - zero
  89. nsec:
  90. push $r9
  91. push $r8
  92. nv_iord($r8, NV_PPWR_TIMER_LOW)
  93. nsec_loop:
  94. nv_iord($r9, NV_PPWR_TIMER_LOW)
  95. sub b32 $r9 $r8
  96. cmp b32 $r9 $r14
  97. bra l #nsec_loop
  98. pop $r8
  99. pop $r9
  100. ret
  101. // busy-wait for a period of time
  102. //
  103. // $r15 - current
  104. // $r14 - addr
  105. // $r13 - mask
  106. // $r12 - data
  107. // $r11 - timeout (ns)
  108. // $r0 - zero
  109. wait:
  110. push $r9
  111. push $r8
  112. nv_iord($r8, NV_PPWR_TIMER_LOW)
  113. wait_loop:
  114. nv_rd32($r10, $r14)
  115. and $r10 $r13
  116. cmp b32 $r10 $r12
  117. bra e #wait_done
  118. nv_iord($r9, NV_PPWR_TIMER_LOW)
  119. sub b32 $r9 $r8
  120. cmp b32 $r9 $r11
  121. bra l #wait_loop
  122. wait_done:
  123. pop $r8
  124. pop $r9
  125. ret
  126. // $r15 - current (kern)
  127. // $r14 - process
  128. // $r8 - NV_PPWR_INTR
  129. intr_watchdog:
  130. // read process' timer status, skip if not enabled
  131. ld b32 $r9 D[$r14 + #proc_time]
  132. cmp b32 $r9 0
  133. bra z #intr_watchdog_next_proc
  134. // subtract last timer's value from process' timer,
  135. // if it's <= 0 then the timer has expired
  136. ld b32 $r10 D[$r0 + #time_prev]
  137. sub b32 $r9 $r10
  138. bra g #intr_watchdog_next_time
  139. mov $r13 KMSG_ALARM
  140. call(send_proc)
  141. clear b32 $r9
  142. bra #intr_watchdog_next_proc
  143. // otherwise, update the next timer's value if this
  144. // process' timer is the soonest
  145. intr_watchdog_next_time:
  146. // ... or if there's no next timer yet
  147. ld b32 $r10 D[$r0 + #time_next]
  148. cmp b32 $r10 0
  149. bra z #intr_watchdog_next_time_set
  150. cmp b32 $r9 $r10
  151. bra g #intr_watchdog_next_proc
  152. intr_watchdog_next_time_set:
  153. st b32 D[$r0 + #time_next] $r9
  154. // update process' timer status, and advance
  155. intr_watchdog_next_proc:
  156. st b32 D[$r14 + #proc_time] $r9
  157. add b32 $r14 #proc_size
  158. cmp b32 $r14 #proc_list_tail
  159. bra ne #intr_watchdog
  160. ret
  161. intr:
  162. push $r0
  163. clear b32 $r0
  164. push $r8
  165. push $r9
  166. push $r10
  167. push $r11
  168. push $r12
  169. push $r13
  170. push $r14
  171. push $r15
  172. mov $r15 #proc_kern
  173. mov $r8 $flags
  174. push $r8
  175. nv_iord($r8, NV_PPWR_DSCRATCH(0))
  176. add b32 $r8 1
  177. nv_iowr(NV_PPWR_DSCRATCH(0), $r8)
  178. nv_iord($r8, NV_PPWR_INTR)
  179. and $r9 $r8 NV_PPWR_INTR_WATCHDOG
  180. bra z #intr_skip_watchdog
  181. st b32 D[$r0 + #time_next] $r0
  182. mov $r14 #proc_list_head
  183. call(intr_watchdog)
  184. ld b32 $r9 D[$r0 + #time_next]
  185. cmp b32 $r9 0
  186. bra z #intr_skip_watchdog
  187. nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9)
  188. st b32 D[$r0 + #time_prev] $r9
  189. intr_skip_watchdog:
  190. and $r9 $r8 NV_PPWR_INTR_SUBINTR
  191. bra z #intr_skip_subintr
  192. nv_iord($r9, NV_PPWR_SUBINTR)
  193. and $r10 $r9 NV_PPWR_SUBINTR_FIFO
  194. bra z #intr_subintr_skip_fifo
  195. nv_iord($r12, NV_PPWR_FIFO_INTR)
  196. push $r12
  197. imm32($r14, PROC_HOST)
  198. mov $r13 KMSG_FIFO
  199. call(send)
  200. pop $r12
  201. nv_iowr(NV_PPWR_FIFO_INTR, $r12)
  202. intr_subintr_skip_fifo:
  203. nv_iowr(NV_PPWR_SUBINTR, $r9)
  204. intr_skip_subintr:
  205. mov $r9 (NV_PPWR_INTR_USER0 | NV_PPWR_INTR_USER1 | NV_PPWR_INTR_PAUSE)
  206. not b32 $r9
  207. and $r8 $r9
  208. nv_iowr(NV_PPWR_INTR_ACK, $r8)
  209. pop $r8
  210. mov $flags $r8
  211. pop $r15
  212. pop $r14
  213. pop $r13
  214. pop $r12
  215. pop $r11
  216. pop $r10
  217. pop $r9
  218. pop $r8
  219. pop $r0
  220. bclr $flags $p0
  221. iret
  222. // calculate the number of ticks in the specified nanoseconds delay
  223. //
  224. // $r15 - current
  225. // $r14 - ns
  226. // $r14 - ticks (return)
  227. // $r0 - zero
  228. ticks_from_ns:
  229. push $r12
  230. push $r11
  231. /* try not losing precision (multiply then divide) */
  232. imm32($r13, HW_TICKS_PER_US)
  233. call(mulu32_32_64)
  234. /* use an immeditate, it's ok because HW_TICKS_PER_US < 16 bits */
  235. div $r12 $r12 1000
  236. /* check if there wasn't any overflow */
  237. cmpu b32 $r11 0
  238. bra e #ticks_from_ns_quit
  239. /* let's divide then multiply, too bad for the precision! */
  240. div $r14 $r14 1000
  241. imm32($r13, HW_TICKS_PER_US)
  242. call(mulu32_32_64)
  243. /* this cannot overflow as long as HW_TICKS_PER_US < 1000 */
  244. ticks_from_ns_quit:
  245. mov b32 $r14 $r12
  246. pop $r11
  247. pop $r12
  248. ret
  249. // calculate the number of ticks in the specified microsecond delay
  250. //
  251. // $r15 - current
  252. // $r14 - us
  253. // $r14 - ticks (return)
  254. // $r0 - zero
  255. ticks_from_us:
  256. push $r12
  257. push $r11
  258. /* simply multiply $us by HW_TICKS_PER_US */
  259. imm32($r13, HW_TICKS_PER_US)
  260. call(mulu32_32_64)
  261. mov b32 $r14 $r12
  262. /* check if there wasn't any overflow */
  263. cmpu b32 $r11 0
  264. bra e #ticks_from_us_quit
  265. /* Overflow! */
  266. clear b32 $r14
  267. ticks_from_us_quit:
  268. pop $r11
  269. pop $r12
  270. ret
  271. // calculate the number of ticks in the specified microsecond delay
  272. //
  273. // $r15 - current
  274. // $r14 - ticks
  275. // $r14 - us (return)
  276. // $r0 - zero
  277. ticks_to_us:
  278. /* simply divide $ticks by HW_TICKS_PER_US */
  279. imm32($r13, HW_TICKS_PER_US)
  280. div $r14 $r14 $r13
  281. ret
  282. // request the current process be sent a message after a timeout expires
  283. //
  284. // $r15 - current
  285. // $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)
  286. // $r0 - zero
  287. timer:
  288. push $r9
  289. push $r8
  290. // interrupts off to prevent racing with timer isr
  291. bclr $flags ie0
  292. // if current process already has a timer set, bail
  293. ld b32 $r8 D[$r15 + #proc_time]
  294. cmp b32 $r8 0
  295. bra g #timer_done
  296. // halt watchdog timer temporarily
  297. clear b32 $r8
  298. nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
  299. // find out how much time elapsed since the last update
  300. // of the watchdog and add this time to the wanted ticks
  301. nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
  302. ld b32 $r9 D[$r0 + #time_prev]
  303. sub b32 $r9 $r8
  304. add b32 $r14 $r9
  305. st b32 D[$r15 + #proc_time] $r14
  306. // check for a pending interrupt. if there's one already
  307. // pending, we can just bail since the timer isr will
  308. // queue the next soonest right after it's done
  309. nv_iord($r8, NV_PPWR_INTR)
  310. and $r8 NV_PPWR_INTR_WATCHDOG
  311. bra nz #timer_enable
  312. // update the watchdog if this timer should expire first,
  313. // or if there's no timeout already set
  314. nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
  315. cmp b32 $r14 $r0
  316. bra e #timer_reset
  317. cmp b32 $r14 $r8
  318. bra g #timer_enable
  319. timer_reset:
  320. nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
  321. st b32 D[$r0 + #time_prev] $r14
  322. // re-enable the watchdog timer
  323. timer_enable:
  324. mov $r8 1
  325. nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
  326. // interrupts back on
  327. timer_done:
  328. bset $flags ie0
  329. pop $r8
  330. pop $r9
  331. ret
  332. // send message to another process
  333. //
  334. // $r15 - current
  335. // $r14 - process
  336. // $r13 - message
  337. // $r12 - message data 0
  338. // $r11 - message data 1
  339. // $r0 - zero
  340. send_proc:
  341. push $r8
  342. push $r9
  343. // check for space in queue
  344. ld b32 $r8 D[$r14 + #proc_qget]
  345. ld b32 $r9 D[$r14 + #proc_qput]
  346. xor $r8 #proc_qmaskb
  347. cmp b32 $r8 $r9
  348. bra e #send_done
  349. // enqueue message
  350. and $r8 $r9 #proc_qmaskp
  351. shl b32 $r8 $r8 #proc_qlen
  352. add b32 $r8 #proc_queue
  353. add b32 $r8 $r14
  354. ld b32 $r10 D[$r15 + #proc_id]
  355. st b32 D[$r8 + #msg_process] $r10
  356. st b32 D[$r8 + #msg_message] $r13
  357. st b32 D[$r8 + #msg_data0] $r12
  358. st b32 D[$r8 + #msg_data1] $r11
  359. // increment PUT
  360. add b32 $r9 1
  361. and $r9 #proc_qmaskf
  362. st b32 D[$r14 + #proc_qput] $r9
  363. bset $flags $p2
  364. send_done:
  365. pop $r9
  366. pop $r8
  367. ret
  368. // lookup process structure by its name
  369. //
  370. // $r15 - current
  371. // $r14 - process name
  372. // $r0 - zero
  373. //
  374. // $r14 - process
  375. // $p1 - success
  376. find:
  377. push $r8
  378. mov $r8 #proc_list_head
  379. bset $flags $p1
  380. find_loop:
  381. ld b32 $r10 D[$r8 + #proc_id]
  382. cmp b32 $r10 $r14
  383. bra e #find_done
  384. add b32 $r8 #proc_size
  385. cmp b32 $r8 #proc_list_tail
  386. bra ne #find_loop
  387. bclr $flags $p1
  388. find_done:
  389. mov b32 $r14 $r8
  390. pop $r8
  391. ret
  392. // send message to another process
  393. //
  394. // $r15 - current
  395. // $r14 - process id
  396. // $r13 - message
  397. // $r12 - message data 0
  398. // $r11 - message data 1
  399. // $r0 - zero
  400. send:
  401. call(find)
  402. bra $p1 #send_proc
  403. ret
  404. // process single message for a given process
  405. //
  406. // $r15 - current
  407. // $r14 - process
  408. // $r0 - zero
  409. recv:
  410. push $r9
  411. push $r8
  412. ld b32 $r8 D[$r14 + #proc_qget]
  413. ld b32 $r9 D[$r14 + #proc_qput]
  414. bclr $flags $p1
  415. cmp b32 $r8 $r9
  416. bra e #recv_done
  417. // dequeue message
  418. and $r9 $r8 #proc_qmaskp
  419. add b32 $r8 1
  420. and $r8 #proc_qmaskf
  421. st b32 D[$r14 + #proc_qget] $r8
  422. ld b32 $r10 D[$r14 + #proc_recv]
  423. push $r15
  424. mov $r15 $flags
  425. push $r15
  426. mov b32 $r15 $r14
  427. shl b32 $r9 $r9 #proc_qlen
  428. add b32 $r14 $r9
  429. add b32 $r14 #proc_queue
  430. ld b32 $r11 D[$r14 + #msg_data1]
  431. ld b32 $r12 D[$r14 + #msg_data0]
  432. ld b32 $r13 D[$r14 + #msg_message]
  433. ld b32 $r14 D[$r14 + #msg_process]
  434. // process it
  435. call $r10
  436. pop $r15
  437. mov $flags $r15
  438. bset $flags $p1
  439. pop $r15
  440. recv_done:
  441. pop $r8
  442. pop $r9
  443. ret
  444. init:
  445. // setup stack
  446. nv_iord($r1, NV_PPWR_CAPS)
  447. extr $r1 $r1 9:17
  448. shl b32 $r1 8
  449. mov $sp $r1
  450. #ifdef NVKM_FALCON_MMIO_UAS
  451. // somehow allows the magic "access mmio via D[]" stuff that's
  452. // used by the nv_rd32/nv_wr32 macros to work
  453. imm32($r1, 0x10 | NV_PPWR_UAS_CONFIG_ENABLE)
  454. nv_iowrs(NV_PPWR_UAS_CONFIG, $r1)
  455. #endif
  456. // route all interrupts except user0/1 and pause to fuc
  457. imm32($r1, 0xe0)
  458. nv_iowr(NV_PPWR_INTR_ROUTE, $r1)
  459. // enable watchdog and subintr intrs
  460. mov $r1 NV_PPWR_INTR_EN_CLR_MASK
  461. nv_iowr(NV_PPWR_INTR_EN_CLR, $r1)
  462. mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG
  463. or $r1 NV_PPWR_INTR_EN_SET_SUBINTR
  464. nv_iowr(NV_PPWR_INTR_EN_SET, $r1)
  465. // enable interrupts globally
  466. imm32($r1, #intr)
  467. and $r1 0xffff
  468. mov $iv0 $r1
  469. bset $flags ie0
  470. // enable watchdog timer
  471. mov $r1 1
  472. nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1)
  473. // bootstrap processes, idle process will be last, and not return
  474. mov $r15 #proc_list_head
  475. init_proc:
  476. ld b32 $r1 D[$r15 + #proc_init]
  477. cmp b32 $r1 0
  478. bra z #init_proc
  479. call $r1
  480. add b32 $r15 #proc_size
  481. bra #init_proc
  482. #endif