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