Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2013 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs
0023  */
0024 
0025 /******************************************************************************
0026  * kernel data segment
0027  *****************************************************************************/
0028 #ifdef INCLUDE_PROC
0029 proc_kern:
0030 process(PROC_KERN, 0, 0)
0031 proc_list_head:
0032 #endif
0033 
0034 #ifdef INCLUDE_DATA
0035 proc_list_tail:
0036 time_prev: .b32 0
0037 time_next: .b32 0
0038 #endif
0039 
0040 /******************************************************************************
0041  * kernel code segment
0042  *****************************************************************************/
0043 #ifdef INCLUDE_CODE
0044         bra #init
0045 
0046 // read nv register
0047 //
0048 // $r15 - current
0049 // $r14 - addr
0050 // $r13 - data (return)
0051 // $r0  - zero
0052 rd32:
0053         nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
0054         imm32($r13, NV_PPWR_MMIO_CTRL_OP_RD | NV_PPWR_MMIO_CTRL_TRIGGER)
0055         nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
0056         rd32_wait:
0057                 nv_iord($r13, NV_PPWR_MMIO_CTRL)
0058                 and $r13 NV_PPWR_MMIO_CTRL_STATUS
0059                 bra nz #rd32_wait
0060         nv_iord($r13, NV_PPWR_MMIO_DATA)
0061         ret
0062 
0063 // write nv register
0064 //
0065 // $r15 - current
0066 // $r14 - addr
0067 // $r13 - data
0068 // $r0  - zero
0069 wr32:
0070         nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
0071         nv_iowr(NV_PPWR_MMIO_DATA, $r13)
0072         imm32($r13, NV_PPWR_MMIO_CTRL_OP_WR | NV_PPWR_MMIO_CTRL_MASK_B32_0 | NV_PPWR_MMIO_CTRL_TRIGGER)
0073 
0074 #ifdef NVKM_FALCON_MMIO_TRAP
0075         push $r13
0076         mov $r13 NV_PPWR_INTR_TRIGGER_USER1
0077         nv_iowr(NV_PPWR_INTR_TRIGGER, $r13)
0078         wr32_host:
0079                 nv_iord($r13, NV_PPWR_INTR)
0080                 and $r13 NV_PPWR_INTR_USER1
0081                 bra nz #wr32_host
0082         pop $r13
0083 #endif
0084 
0085         nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
0086         wr32_wait:
0087                 nv_iord($r13, NV_PPWR_MMIO_CTRL)
0088                 and $r13 NV_PPWR_MMIO_CTRL_STATUS
0089                 bra nz #wr32_wait
0090         ret
0091 
0092 // busy-wait for a period of time
0093 //
0094 // $r15 - current
0095 // $r14 - ns
0096 // $r0  - zero
0097 nsec:
0098         push $r9
0099         push $r8
0100         nv_iord($r8, NV_PPWR_TIMER_LOW)
0101         nsec_loop:
0102                 nv_iord($r9, NV_PPWR_TIMER_LOW)
0103                 sub b32 $r9 $r8
0104                 cmp b32 $r9 $r14
0105                 bra l #nsec_loop
0106         pop $r8
0107         pop $r9
0108         ret
0109 
0110 // busy-wait for a period of time
0111 //
0112 // $r15 - current
0113 // $r14 - addr
0114 // $r13 - mask
0115 // $r12 - data
0116 // $r11 - timeout (ns)
0117 // $r0  - zero
0118 wait:
0119         push $r9
0120         push $r8
0121         nv_iord($r8, NV_PPWR_TIMER_LOW)
0122         wait_loop:
0123                 nv_rd32($r10, $r14)
0124                 and $r10 $r13
0125                 cmp b32 $r10 $r12
0126                 bra e #wait_done
0127                 nv_iord($r9, NV_PPWR_TIMER_LOW)
0128                 sub b32 $r9 $r8
0129                 cmp b32 $r9 $r11
0130                 bra l #wait_loop
0131         wait_done:
0132         pop $r8
0133         pop $r9
0134         ret
0135 
0136 // $r15 - current (kern)
0137 // $r14 - process
0138 // $r8  - NV_PPWR_INTR
0139 intr_watchdog:
0140         // read process' timer status, skip if not enabled
0141         ld b32 $r9 D[$r14 + #proc_time]
0142         cmp b32 $r9 0
0143         bra z #intr_watchdog_next_proc
0144 
0145         // subtract last timer's value from process' timer,
0146         // if it's <= 0 then the timer has expired
0147         ld b32 $r10 D[$r0 + #time_prev]
0148         sub b32 $r9 $r10
0149         bra g #intr_watchdog_next_time
0150                 mov $r13 KMSG_ALARM
0151                 call(send_proc)
0152                 clear b32 $r9
0153                 bra #intr_watchdog_next_proc
0154 
0155         // otherwise, update the next timer's value if this
0156         // process' timer is the soonest
0157         intr_watchdog_next_time:
0158                 // ... or if there's no next timer yet
0159                 ld b32 $r10 D[$r0 + #time_next]
0160                 cmp b32 $r10 0
0161                 bra z #intr_watchdog_next_time_set
0162 
0163                 cmp b32 $r9 $r10
0164                 bra g #intr_watchdog_next_proc
0165                 intr_watchdog_next_time_set:
0166                 st b32 D[$r0 + #time_next] $r9
0167 
0168         // update process' timer status, and advance
0169         intr_watchdog_next_proc:
0170         st b32 D[$r14 + #proc_time] $r9
0171         add b32 $r14 #proc_size
0172         cmp b32 $r14 #proc_list_tail
0173         bra ne #intr_watchdog
0174         ret
0175 
0176 intr:
0177         push $r0
0178         clear b32 $r0
0179         push $r8
0180         push $r9
0181         push $r10
0182         push $r11
0183         push $r12
0184         push $r13
0185         push $r14
0186         push $r15
0187         mov $r15 #proc_kern
0188         mov $r8 $flags
0189         push $r8
0190 
0191         nv_iord($r8, NV_PPWR_DSCRATCH(0))
0192         add b32 $r8 1
0193         nv_iowr(NV_PPWR_DSCRATCH(0), $r8)
0194 
0195         nv_iord($r8, NV_PPWR_INTR)
0196         and $r9 $r8 NV_PPWR_INTR_WATCHDOG
0197         bra z #intr_skip_watchdog
0198                 st b32 D[$r0 + #time_next] $r0
0199                 mov $r14 #proc_list_head
0200                 call(intr_watchdog)
0201                 ld b32 $r9 D[$r0 + #time_next]
0202                 cmp b32 $r9 0
0203                 bra z #intr_skip_watchdog
0204                         nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9)
0205                         st b32 D[$r0 + #time_prev] $r9
0206 
0207         intr_skip_watchdog:
0208         and $r9 $r8 NV_PPWR_INTR_SUBINTR
0209         bra z #intr_skip_subintr
0210                 nv_iord($r9, NV_PPWR_SUBINTR)
0211                 and $r10 $r9 NV_PPWR_SUBINTR_FIFO
0212                 bra z #intr_subintr_skip_fifo
0213                         nv_iord($r12, NV_PPWR_FIFO_INTR)
0214                         push $r12
0215                         imm32($r14, PROC_HOST)
0216                         mov $r13 KMSG_FIFO
0217                         call(send)
0218                         pop $r12
0219                         nv_iowr(NV_PPWR_FIFO_INTR, $r12)
0220                 intr_subintr_skip_fifo:
0221                 nv_iowr(NV_PPWR_SUBINTR, $r9)
0222 
0223         intr_skip_subintr:
0224         mov $r9 (NV_PPWR_INTR_USER0 | NV_PPWR_INTR_USER1 | NV_PPWR_INTR_PAUSE)
0225         not b32 $r9
0226         and $r8 $r9
0227         nv_iowr(NV_PPWR_INTR_ACK, $r8)
0228 
0229         pop $r8
0230         mov $flags $r8
0231         pop $r15
0232         pop $r14
0233         pop $r13
0234         pop $r12
0235         pop $r11
0236         pop $r10
0237         pop $r9
0238         pop $r8
0239         pop $r0
0240         bclr $flags $p0
0241         iret
0242 
0243 // calculate the number of ticks in the specified nanoseconds delay
0244 //
0245 // $r15 - current
0246 // $r14 - ns
0247 // $r14 - ticks (return)
0248 // $r0  - zero
0249 ticks_from_ns:
0250         push $r12
0251         push $r11
0252 
0253         /* try not losing precision (multiply then divide) */
0254         imm32($r13, HW_TICKS_PER_US)
0255         call(mulu32_32_64)
0256 
0257         /* use an immeditate, it's ok because HW_TICKS_PER_US < 16 bits */
0258         div $r12 $r12 1000
0259 
0260         /* check if there wasn't any overflow */
0261         cmpu b32 $r11 0
0262         bra e #ticks_from_ns_quit
0263 
0264         /* let's divide then multiply, too bad for the precision! */
0265         div $r14 $r14 1000
0266         imm32($r13, HW_TICKS_PER_US)
0267         call(mulu32_32_64)
0268 
0269         /* this cannot overflow as long as HW_TICKS_PER_US < 1000 */
0270 
0271 ticks_from_ns_quit:
0272         mov b32 $r14 $r12
0273         pop $r11
0274         pop $r12
0275         ret
0276 
0277 // calculate the number of ticks in the specified microsecond delay
0278 //
0279 // $r15 - current
0280 // $r14 - us
0281 // $r14 - ticks (return)
0282 // $r0  - zero
0283 ticks_from_us:
0284         push $r12
0285         push $r11
0286 
0287         /* simply multiply $us by HW_TICKS_PER_US */
0288         imm32($r13, HW_TICKS_PER_US)
0289         call(mulu32_32_64)
0290         mov b32 $r14 $r12
0291 
0292         /* check if there wasn't any overflow */
0293         cmpu b32 $r11 0
0294         bra e #ticks_from_us_quit
0295 
0296         /* Overflow! */
0297         clear b32 $r14
0298 
0299 ticks_from_us_quit:
0300         pop $r11
0301         pop $r12
0302         ret
0303 
0304 // calculate the number of ticks in the specified microsecond delay
0305 //
0306 // $r15 - current
0307 // $r14 - ticks
0308 // $r14 - us (return)
0309 // $r0  - zero
0310 ticks_to_us:
0311         /* simply divide $ticks by HW_TICKS_PER_US */
0312         imm32($r13, HW_TICKS_PER_US)
0313         div $r14 $r14 $r13
0314 
0315         ret
0316 
0317 // request the current process be sent a message after a timeout expires
0318 //
0319 // $r15 - current
0320 // $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)
0321 // $r0  - zero
0322 timer:
0323         push $r9
0324         push $r8
0325 
0326         // interrupts off to prevent racing with timer isr
0327         bclr $flags ie0
0328 
0329         // if current process already has a timer set, bail
0330         ld b32 $r8 D[$r15 + #proc_time]
0331         cmp b32 $r8 0
0332         bra g #timer_done
0333 
0334         // halt watchdog timer temporarily
0335         clear b32 $r8
0336         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
0337 
0338         // find out how much time elapsed since the last update
0339         // of the watchdog and add this time to the wanted ticks
0340         nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
0341         ld b32 $r9 D[$r0 + #time_prev]
0342         sub b32 $r9 $r8
0343         add b32 $r14 $r9
0344         st b32 D[$r15 + #proc_time] $r14
0345 
0346         // check for a pending interrupt.  if there's one already
0347         // pending, we can just bail since the timer isr will
0348         // queue the next soonest right after it's done
0349         nv_iord($r8, NV_PPWR_INTR)
0350         and $r8 NV_PPWR_INTR_WATCHDOG
0351         bra nz #timer_enable
0352 
0353         // update the watchdog if this timer should expire first,
0354         // or if there's no timeout already set
0355         nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
0356         cmp b32 $r14 $r0
0357         bra e #timer_reset
0358         cmp b32 $r14 $r8
0359         bra g #timer_enable
0360                 timer_reset:
0361                 nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
0362                 st b32 D[$r0 + #time_prev] $r14
0363 
0364         // re-enable the watchdog timer
0365         timer_enable:
0366         mov $r8 1
0367         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
0368 
0369         // interrupts back on
0370         timer_done:
0371         bset $flags ie0
0372 
0373         pop $r8
0374         pop $r9
0375         ret
0376 
0377 // send message to another process
0378 //
0379 // $r15 - current
0380 // $r14 - process
0381 // $r13 - message
0382 // $r12 - message data 0
0383 // $r11 - message data 1
0384 // $r0  - zero
0385 send_proc:
0386         push $r8
0387         push $r9
0388         // check for space in queue
0389         ld b32 $r8 D[$r14 + #proc_qget]
0390         ld b32 $r9 D[$r14 + #proc_qput]
0391         xor $r8 #proc_qmaskb
0392         cmp b32 $r8 $r9
0393         bra e #send_done
0394 
0395         // enqueue message
0396         and $r8 $r9 #proc_qmaskp
0397         shl b32 $r8 $r8 #proc_qlen
0398         add b32 $r8 #proc_queue
0399         add b32 $r8 $r14
0400 
0401         ld b32 $r10 D[$r15 + #proc_id]
0402         st b32 D[$r8 + #msg_process] $r10
0403         st b32 D[$r8 + #msg_message] $r13
0404         st b32 D[$r8 + #msg_data0] $r12
0405         st b32 D[$r8 + #msg_data1] $r11
0406 
0407         // increment PUT
0408         add b32 $r9 1
0409         and $r9 #proc_qmaskf
0410         st b32 D[$r14 + #proc_qput] $r9
0411         bset $flags $p2
0412         send_done:
0413         pop $r9
0414         pop $r8
0415         ret
0416 
0417 // lookup process structure by its name
0418 //
0419 // $r15 - current
0420 // $r14 - process name
0421 // $r0  - zero
0422 //
0423 // $r14 - process
0424 // $p1  - success
0425 find:
0426         push $r8
0427         mov $r8 #proc_list_head
0428         bset $flags $p1
0429         find_loop:
0430                 ld b32 $r10 D[$r8 + #proc_id]
0431                 cmp b32 $r10 $r14
0432                 bra e #find_done
0433                 add b32 $r8 #proc_size
0434                 cmp b32 $r8 #proc_list_tail
0435                 bra ne #find_loop
0436                 bclr $flags $p1
0437         find_done:
0438         mov b32 $r14 $r8
0439         pop $r8
0440         ret
0441 
0442 // send message to another process
0443 //
0444 // $r15 - current
0445 // $r14 - process id
0446 // $r13 - message
0447 // $r12 - message data 0
0448 // $r11 - message data 1
0449 // $r0  - zero
0450 send:
0451         call(find)
0452         bra $p1 #send_proc
0453         ret
0454 
0455 // process single message for a given process
0456 //
0457 // $r15 - current
0458 // $r14 - process
0459 // $r0  - zero
0460 recv:
0461         push $r9
0462         push $r8
0463 
0464         ld b32 $r8 D[$r14 + #proc_qget]
0465         ld b32 $r9 D[$r14 + #proc_qput]
0466         bclr $flags $p1
0467         cmp b32 $r8 $r9
0468         bra e #recv_done
0469                 // dequeue message
0470                 and $r9 $r8 #proc_qmaskp
0471                 add b32 $r8 1
0472                 and $r8 #proc_qmaskf
0473                 st b32 D[$r14 + #proc_qget] $r8
0474                 ld b32 $r10 D[$r14 + #proc_recv]
0475 
0476                 push $r15
0477                 mov $r15 $flags
0478                 push $r15
0479                 mov b32 $r15 $r14
0480 
0481                 shl b32 $r9 $r9 #proc_qlen
0482                 add b32 $r14 $r9
0483                 add b32 $r14 #proc_queue
0484                 ld b32 $r11 D[$r14 + #msg_data1]
0485                 ld b32 $r12 D[$r14 + #msg_data0]
0486                 ld b32 $r13 D[$r14 + #msg_message]
0487                 ld b32 $r14 D[$r14 + #msg_process]
0488 
0489                 // process it
0490                 call $r10
0491                 pop $r15
0492                 mov $flags $r15
0493                 bset $flags $p1
0494                 pop $r15
0495         recv_done:
0496         pop $r8
0497         pop $r9
0498         ret
0499 
0500 init:
0501         // setup stack
0502         nv_iord($r1, NV_PPWR_CAPS)
0503         extr $r1 $r1 9:17
0504         shl b32 $r1 8
0505         mov $sp $r1
0506 
0507 #ifdef NVKM_FALCON_MMIO_UAS
0508         // somehow allows the magic "access mmio via D[]" stuff that's
0509         // used by the nv_rd32/nv_wr32 macros to work
0510         imm32($r1, 0x10 | NV_PPWR_UAS_CONFIG_ENABLE)
0511         nv_iowrs(NV_PPWR_UAS_CONFIG, $r1)
0512 #endif
0513 
0514         // route all interrupts except user0/1 and pause to fuc
0515         imm32($r1, 0xe0)
0516         nv_iowr(NV_PPWR_INTR_ROUTE, $r1)
0517 
0518         // enable watchdog and subintr intrs
0519         mov $r1 NV_PPWR_INTR_EN_CLR_MASK
0520         nv_iowr(NV_PPWR_INTR_EN_CLR, $r1)
0521         mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG
0522         or $r1 NV_PPWR_INTR_EN_SET_SUBINTR
0523         nv_iowr(NV_PPWR_INTR_EN_SET, $r1)
0524 
0525         // enable interrupts globally
0526         imm32($r1, #intr)
0527         and $r1 0xffff
0528         mov $iv0 $r1
0529         bset $flags ie0
0530 
0531         // enable watchdog timer
0532         mov $r1 1
0533         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1)
0534 
0535         // bootstrap processes, idle process will be last, and not return
0536         mov $r15 #proc_list_head
0537         init_proc:
0538                 ld b32 $r1 D[$r15 + #proc_init]
0539                 cmp b32 $r1 0
0540                 bra z #init_proc
0541                 call $r1
0542                 add b32 $r15 #proc_size
0543                 bra #init_proc
0544 #endif