Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / gpu / drm / nouveau / nvkm / subdev / pmu / fuc / kernel.fuc
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 /******************************************************************************
26  * kernel data segment
27  *****************************************************************************/
28 #ifdef INCLUDE_PROC
29 proc_kern:
30 process(PROC_KERN, 0, 0)
31 proc_list_head:
32 #endif
33
34 #ifdef INCLUDE_DATA
35 proc_list_tail:
36 time_prev: .b32 0
37 time_next: .b32 0
38 #endif
39
40 /******************************************************************************
41  * kernel code segment
42  *****************************************************************************/
43 #ifdef INCLUDE_CODE
44         bra #init
45
46 // read nv register
47 //
48 // $r15 - current
49 // $r14 - addr
50 // $r13 - data (return)
51 // $r0  - zero
52 rd32:
53         nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
54         mov $r13 NV_PPWR_MMIO_CTRL_OP_RD
55         sethi $r13 NV_PPWR_MMIO_CTRL_TRIGGER
56         nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
57         rd32_wait:
58                 nv_iord($r13, NV_PPWR_MMIO_CTRL)
59                 and $r13 NV_PPWR_MMIO_CTRL_STATUS
60                 bra nz #rd32_wait
61         nv_iord($r13, NV_PPWR_MMIO_DATA)
62         ret
63
64 // write nv register
65 //
66 // $r15 - current
67 // $r14 - addr
68 // $r13 - data
69 // $r0  - zero
70 wr32:
71         nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
72         nv_iowr(NV_PPWR_MMIO_DATA, $r13)
73         mov $r13 NV_PPWR_MMIO_CTRL_OP_WR
74         or $r13 NV_PPWR_MMIO_CTRL_MASK_B32_0
75         sethi $r13 NV_PPWR_MMIO_CTRL_TRIGGER
76
77 #ifdef NVKM_FALCON_MMIO_TRAP
78         push $r13
79         mov $r13 NV_PPWR_INTR_TRIGGER_USER1
80         nv_iowr(NV_PPWR_INTR_TRIGGER, $r13)
81         wr32_host:
82                 nv_iord($r13, NV_PPWR_INTR)
83                 and $r13 NV_PPWR_INTR_USER1
84                 bra nz #wr32_host
85         pop $r13
86 #endif
87
88         nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
89         wr32_wait:
90                 nv_iord($r13, NV_PPWR_MMIO_CTRL)
91                 and $r13 NV_PPWR_MMIO_CTRL_STATUS
92                 bra nz #wr32_wait
93         ret
94
95 // busy-wait for a period of time
96 //
97 // $r15 - current
98 // $r14 - ns
99 // $r0  - zero
100 nsec:
101         push $r9
102         push $r8
103         nv_iord($r8, NV_PPWR_TIMER_LOW)
104         nsec_loop:
105                 nv_iord($r9, NV_PPWR_TIMER_LOW)
106                 sub b32 $r9 $r8
107                 cmp b32 $r9 $r14
108                 bra l #nsec_loop
109         pop $r8
110         pop $r9
111         ret
112
113 // busy-wait for a period of time
114 //
115 // $r15 - current
116 // $r14 - addr
117 // $r13 - mask
118 // $r12 - data
119 // $r11 - timeout (ns)
120 // $r0  - zero
121 wait:
122         push $r9
123         push $r8
124         nv_iord($r8, NV_PPWR_TIMER_LOW)
125         wait_loop:
126                 nv_rd32($r10, $r14)
127                 and $r10 $r13
128                 cmp b32 $r10 $r12
129                 bra e #wait_done
130                 nv_iord($r9, NV_PPWR_TIMER_LOW)
131                 sub b32 $r9 $r8
132                 cmp b32 $r9 $r11
133                 bra l #wait_loop
134         wait_done:
135         pop $r8
136         pop $r9
137         ret
138
139 // $r15 - current (kern)
140 // $r14 - process
141 // $r8  - NV_PPWR_INTR
142 intr_watchdog:
143         // read process' timer status, skip if not enabled
144         ld b32 $r9 D[$r14 + #proc_time]
145         cmp b32 $r9 0
146         bra z #intr_watchdog_next_proc
147
148         // subtract last timer's value from process' timer,
149         // if it's <= 0 then the timer has expired
150         ld b32 $r10 D[$r0 + #time_prev]
151         sub b32 $r9 $r10
152         bra g #intr_watchdog_next_time
153                 mov $r13 KMSG_ALARM
154                 call(send_proc)
155                 clear b32 $r9
156                 bra #intr_watchdog_next_proc
157
158         // otherwise, update the next timer's value if this
159         // process' timer is the soonest
160         intr_watchdog_next_time:
161                 // ... or if there's no next timer yet
162                 ld b32 $r10 D[$r0 + #time_next]
163                 cmp b32 $r10 0
164                 bra z #intr_watchdog_next_time_set
165
166                 cmp b32 $r9 $r10
167                 bra g #intr_watchdog_next_proc
168                 intr_watchdog_next_time_set:
169                 st b32 D[$r0 + #time_next] $r9
170
171         // update process' timer status, and advance
172         intr_watchdog_next_proc:
173         st b32 D[$r14 + #proc_time] $r9
174         add b32 $r14 #proc_size
175         cmp b32 $r14 #proc_list_tail
176         bra ne #intr_watchdog
177         ret
178
179 intr:
180         push $r0
181         clear b32 $r0
182         push $r8
183         push $r9
184         push $r10
185         push $r11
186         push $r12
187         push $r13
188         push $r14
189         push $r15
190         mov $r15 #proc_kern
191         mov $r8 $flags
192         push $r8
193
194         nv_iord($r8, NV_PPWR_DSCRATCH(0))
195         add b32 $r8 1
196         nv_iowr(NV_PPWR_DSCRATCH(0), $r8)
197
198         nv_iord($r8, NV_PPWR_INTR)
199         and $r9 $r8 NV_PPWR_INTR_WATCHDOG
200         bra z #intr_skip_watchdog
201                 st b32 D[$r0 + #time_next] $r0
202                 mov $r14 #proc_list_head
203                 call(intr_watchdog)
204                 ld b32 $r9 D[$r0 + #time_next]
205                 cmp b32 $r9 0
206                 bra z #intr_skip_watchdog
207                         nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9)
208                         st b32 D[$r0 + #time_prev] $r9
209
210         intr_skip_watchdog:
211         and $r9 $r8 NV_PPWR_INTR_SUBINTR
212         bra z #intr_skip_subintr
213                 nv_iord($r9, NV_PPWR_SUBINTR)
214                 and $r10 $r9 NV_PPWR_SUBINTR_FIFO
215                 bra z #intr_subintr_skip_fifo
216                         nv_iord($r12, NV_PPWR_FIFO_INTR)
217                         push $r12
218                         mov $r14 (PROC_HOST & 0x0000ffff)
219                         sethi $r14 (PROC_HOST & 0xffff0000)
220                         mov $r13 KMSG_FIFO
221                         call(send)
222                         pop $r12
223                         nv_iowr(NV_PPWR_FIFO_INTR, $r12)
224                 intr_subintr_skip_fifo:
225                 nv_iowr(NV_PPWR_SUBINTR, $r9)
226
227         intr_skip_subintr:
228         and $r9 $r8 NV_PPWR_INTR_PAUSE
229         bra z #intr_skip_pause
230                 and $r10 0xffbf
231
232         intr_skip_pause:
233         and $r9 $r8 NV_PPWR_INTR_USER0
234         bra z #intr_skip_user0
235                 and $r10 0xffbf
236
237         intr_skip_user0:
238         nv_iowr(NV_PPWR_INTR_ACK, $r8)
239         pop $r8
240         mov $flags $r8
241         pop $r15
242         pop $r14
243         pop $r13
244         pop $r12
245         pop $r11
246         pop $r10
247         pop $r9
248         pop $r8
249         pop $r0
250         bclr $flags $p0
251         iret
252
253 // calculate the number of ticks in the specified nanoseconds delay
254 //
255 // $r15 - current
256 // $r14 - ns
257 // $r14 - ticks (return)
258 // $r0  - zero
259 ticks_from_ns:
260         push $r12
261         push $r11
262
263         /* try not losing precision (multiply then divide) */
264         imm32($r13, HW_TICKS_PER_US)
265         call #mulu32_32_64
266
267         /* use an immeditate, it's ok because HW_TICKS_PER_US < 16 bits */
268         div $r12 $r12 1000
269
270         /* check if there wasn't any overflow */
271         cmpu b32 $r11 0
272         bra e #ticks_from_ns_quit
273
274         /* let's divide then multiply, too bad for the precision! */
275         div $r14 $r14 1000
276         imm32($r13, HW_TICKS_PER_US)
277         call #mulu32_32_64
278
279         /* this cannot overflow as long as HW_TICKS_PER_US < 1000 */
280
281 ticks_from_ns_quit:
282         mov b32 $r14 $r12
283         pop $r11
284         pop $r12
285         ret
286
287 // calculate the number of ticks in the specified microsecond delay
288 //
289 // $r15 - current
290 // $r14 - us
291 // $r14 - ticks (return)
292 // $r0  - zero
293 ticks_from_us:
294         push $r12
295         push $r11
296
297         /* simply multiply $us by HW_TICKS_PER_US */
298         imm32($r13, HW_TICKS_PER_US)
299         call #mulu32_32_64
300         mov b32 $r14 $r12
301
302         /* check if there wasn't any overflow */
303         cmpu b32 $r11 0
304         bra e #ticks_from_us_quit
305
306         /* Overflow! */
307         clear b32 $r14
308
309 ticks_from_us_quit:
310         pop $r11
311         pop $r12
312         ret
313
314 // calculate the number of ticks in the specified microsecond delay
315 //
316 // $r15 - current
317 // $r14 - ticks
318 // $r14 - us (return)
319 // $r0  - zero
320 ticks_to_us:
321         /* simply divide $ticks by HW_TICKS_PER_US */
322         imm32($r13, HW_TICKS_PER_US)
323         div $r14 $r14 $r13
324
325         ret
326
327 // request the current process be sent a message after a timeout expires
328 //
329 // $r15 - current
330 // $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)
331 // $r0  - zero
332 timer:
333         push $r9
334         push $r8
335
336         // interrupts off to prevent racing with timer isr
337         bclr $flags ie0
338
339         // if current process already has a timer set, bail
340         ld b32 $r8 D[$r15 + #proc_time]
341         cmp b32 $r8 0
342         bra g #timer_done
343
344         // halt watchdog timer temporarily
345         clear b32 $r8
346         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
347
348         // find out how much time elapsed since the last update
349         // of the watchdog and add this time to the wanted ticks
350         nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
351         ld b32 $r9 D[$r0 + #time_prev]
352         sub b32 $r9 $r8
353         add b32 $r14 $r9
354         st b32 D[$r15 + #proc_time] $r14
355
356         // check for a pending interrupt.  if there's one already
357         // pending, we can just bail since the timer isr will
358         // queue the next soonest right after it's done
359         nv_iord($r8, NV_PPWR_INTR)
360         and $r8 NV_PPWR_INTR_WATCHDOG
361         bra nz #timer_enable
362
363         // update the watchdog if this timer should expire first,
364         // or if there's no timeout already set
365         nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
366         cmp b32 $r14 $r0
367         bra e #timer_reset
368         cmp b32 $r14 $r8
369         bra g #timer_enable
370                 timer_reset:
371                 nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
372                 st b32 D[$r0 + #time_prev] $r14
373
374         // re-enable the watchdog timer
375         timer_enable:
376         mov $r8 1
377         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
378
379         // interrupts back on
380         timer_done:
381         bset $flags ie0
382
383         pop $r8
384         pop $r9
385         ret
386
387 // send message to another process
388 //
389 // $r15 - current
390 // $r14 - process
391 // $r13 - message
392 // $r12 - message data 0
393 // $r11 - message data 1
394 // $r0  - zero
395 send_proc:
396         push $r8
397         push $r9
398         // check for space in queue
399         ld b32 $r8 D[$r14 + #proc_qget]
400         ld b32 $r9 D[$r14 + #proc_qput]
401         xor $r8 #proc_qmaskb
402         cmp b32 $r8 $r9
403         bra e #send_done
404
405         // enqueue message
406         and $r8 $r9 #proc_qmaskp
407         shl b32 $r8 $r8 #proc_qlen
408         add b32 $r8 #proc_queue
409         add b32 $r8 $r14
410
411         ld b32 $r10 D[$r15 + #proc_id]
412         st b32 D[$r8 + #msg_process] $r10
413         st b32 D[$r8 + #msg_message] $r13
414         st b32 D[$r8 + #msg_data0] $r12
415         st b32 D[$r8 + #msg_data1] $r11
416
417         // increment PUT
418         add b32 $r9 1
419         and $r9 #proc_qmaskf
420         st b32 D[$r14 + #proc_qput] $r9
421         bset $flags $p2
422         send_done:
423         pop $r9
424         pop $r8
425         ret
426
427 // lookup process structure by its name
428 //
429 // $r15 - current
430 // $r14 - process name
431 // $r0  - zero
432 //
433 // $r14 - process
434 // $p1  - success
435 find:
436         push $r8
437         mov $r8 #proc_list_head
438         bset $flags $p1
439         find_loop:
440                 ld b32 $r10 D[$r8 + #proc_id]
441                 cmp b32 $r10 $r14
442                 bra e #find_done
443                 add b32 $r8 #proc_size
444                 cmp b32 $r8 #proc_list_tail
445                 bra ne #find_loop
446                 bclr $flags $p1
447         find_done:
448         mov b32 $r14 $r8
449         pop $r8
450         ret
451
452 // send message to another process
453 //
454 // $r15 - current
455 // $r14 - process id
456 // $r13 - message
457 // $r12 - message data 0
458 // $r11 - message data 1
459 // $r0  - zero
460 send:
461         call(find)
462         bra $p1 #send_proc
463         ret
464
465 // process single message for a given process
466 //
467 // $r15 - current
468 // $r14 - process
469 // $r0  - zero
470 recv:
471         push $r9
472         push $r8
473
474         ld b32 $r8 D[$r14 + #proc_qget]
475         ld b32 $r9 D[$r14 + #proc_qput]
476         bclr $flags $p1
477         cmp b32 $r8 $r9
478         bra e #recv_done
479                 // dequeue message
480                 and $r9 $r8 #proc_qmaskp
481                 add b32 $r8 1
482                 and $r8 #proc_qmaskf
483                 st b32 D[$r14 + #proc_qget] $r8
484                 ld b32 $r10 D[$r14 + #proc_recv]
485
486                 push $r15
487                 mov $r15 $flags
488                 push $r15
489                 mov b32 $r15 $r14
490
491                 shl b32 $r9 $r9 #proc_qlen
492                 add b32 $r14 $r9
493                 add b32 $r14 #proc_queue
494                 ld b32 $r11 D[$r14 + #msg_data1]
495                 ld b32 $r12 D[$r14 + #msg_data0]
496                 ld b32 $r13 D[$r14 + #msg_message]
497                 ld b32 $r14 D[$r14 + #msg_process]
498
499                 // process it
500                 call $r10
501                 pop $r15
502                 mov $flags $r15
503                 bset $flags $p1
504                 pop $r15
505         recv_done:
506         pop $r8
507         pop $r9
508         ret
509
510 init:
511         // setup stack
512         nv_iord($r1, NV_PPWR_CAPS)
513         extr $r1 $r1 9:17
514         shl b32 $r1 8
515         mov $sp $r1
516
517 #ifdef NVKM_FALCON_MMIO_UAS
518         // somehow allows the magic "access mmio via D[]" stuff that's
519         // used by the nv_rd32/nv_wr32 macros to work
520         mov $r1 0x0010
521         sethi $r1 NV_PPWR_UAS_CONFIG_ENABLE
522         nv_iowrs(NV_PPWR_UAS_CONFIG, $r1)
523 #endif
524
525         // route all interrupts except user0/1 and pause to fuc
526         mov $r1 0x00e0
527         sethi $r1 0x00000000
528         nv_iowr(NV_PPWR_INTR_ROUTE, $r1)
529
530         // enable watchdog and subintr intrs
531         mov $r1 NV_PPWR_INTR_EN_CLR_MASK
532         nv_iowr(NV_PPWR_INTR_EN_CLR, $r1)
533         mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG
534         or $r1 NV_PPWR_INTR_EN_SET_SUBINTR
535         nv_iowr(NV_PPWR_INTR_EN_SET, $r1)
536
537         // enable interrupts globally
538         mov $r1 #intr
539         sethi $r1 0x00000000
540         mov $iv0 $r1
541         bset $flags ie0
542
543         // enable watchdog timer
544         mov $r1 1
545         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1)
546
547         // bootstrap processes, idle process will be last, and not return
548         mov $r15 #proc_list_head
549         init_proc:
550                 ld b32 $r1 D[$r15 + #proc_init]
551                 cmp b32 $r1 0
552                 bra z #init_proc
553                 call $r1
554                 add b32 $r15 #proc_size
555                 bra #init_proc
556 #endif