brintos

brintos / linux-shallow public Read only

0
0
Text · 11.6 KiB · c20a3bd Raw
545 lines · plain
1/*2 * Copyright 2013 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Ben Skeggs23 */24 25/******************************************************************************26 * kernel data segment27 *****************************************************************************/28#ifdef INCLUDE_PROC29proc_kern:30process(PROC_KERN, 0, 0)31proc_list_head:32#endif33 34#ifdef INCLUDE_DATA35proc_list_tail:36time_prev: .b32 037time_next: .b32 038#endif39 40/******************************************************************************41 * kernel code segment42 *****************************************************************************/43#ifdef INCLUDE_CODE44	bra #init45 46// read nv register47//48// $r15 - current49// $r14 - addr50// $r13 - data (return)51// $r0  - zero52rd32: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_STATUS59		bra nz #rd32_wait60	nv_iord($r13, NV_PPWR_MMIO_DATA)61	ret62 63// write nv register64//65// $r15 - current66// $r14 - addr67// $r13 - data68// $r0  - zero69wr32: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_TRAP75	push $r1376	mov $r13 NV_PPWR_INTR_TRIGGER_USER177	nv_iowr(NV_PPWR_INTR_TRIGGER, $r13)78	wr32_host:79		nv_iord($r13, NV_PPWR_INTR)80		and $r13 NV_PPWR_INTR_USER181		bra nz #wr32_host82	pop $r1383#endif84 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_STATUS89		bra nz #wr32_wait90	ret91 92// busy-wait for a period of time93//94// $r15 - current95// $r14 - ns96// $r0  - zero97nsec:98	push $r999	push $r8100	nv_iord($r8, NV_PPWR_TIMER_LOW)101	nsec_loop:102		nv_iord($r9, NV_PPWR_TIMER_LOW)103		sub b32 $r9 $r8104		cmp b32 $r9 $r14105		bra l #nsec_loop106	pop $r8107	pop $r9108	ret109 110// busy-wait for a period of time111//112// $r15 - current113// $r14 - addr114// $r13 - mask115// $r12 - data116// $r11 - timeout (ns)117// $r0  - zero118wait:119	push $r9120	push $r8121	nv_iord($r8, NV_PPWR_TIMER_LOW)122	wait_loop:123		nv_rd32($r10, $r14)124		and $r10 $r13125		cmp b32 $r10 $r12126		bra e #wait_done127		nv_iord($r9, NV_PPWR_TIMER_LOW)128		sub b32 $r9 $r8129		cmp b32 $r9 $r11130		bra l #wait_loop131	wait_done:132	pop $r8133	pop $r9134	ret135 136// $r15 - current (kern)137// $r14 - process138// $r8  - NV_PPWR_INTR139intr_watchdog:140	// read process' timer status, skip if not enabled141	ld b32 $r9 D[$r14 + #proc_time]142	cmp b32 $r9 0143	bra z #intr_watchdog_next_proc144 145	// subtract last timer's value from process' timer,146	// if it's <= 0 then the timer has expired147	ld b32 $r10 D[$r0 + #time_prev]148	sub b32 $r9 $r10149	bra g #intr_watchdog_next_time150		mov $r13 KMSG_ALARM151		call(send_proc)152		clear b32 $r9153		bra #intr_watchdog_next_proc154 155	// otherwise, update the next timer's value if this156	// process' timer is the soonest157	intr_watchdog_next_time:158		// ... or if there's no next timer yet159		ld b32 $r10 D[$r0 + #time_next]160		cmp b32 $r10 0161		bra z #intr_watchdog_next_time_set162 163		cmp b32 $r9 $r10164		bra g #intr_watchdog_next_proc165		intr_watchdog_next_time_set:166		st b32 D[$r0 + #time_next] $r9167 168	// update process' timer status, and advance169	intr_watchdog_next_proc:170	st b32 D[$r14 + #proc_time] $r9171	add b32 $r14 #proc_size172	cmp b32 $r14 #proc_list_tail173	bra ne #intr_watchdog174	ret175 176intr:177	push $r0178	clear b32 $r0179	push $r8180	push $r9181	push $r10182	push $r11183	push $r12184	push $r13185	push $r14186	push $r15187	mov $r15 #proc_kern188	mov $r8 $flags189	push $r8190 191	nv_iord($r8, NV_PPWR_DSCRATCH(0))192	add b32 $r8 1193	nv_iowr(NV_PPWR_DSCRATCH(0), $r8)194 195	nv_iord($r8, NV_PPWR_INTR)196	and $r9 $r8 NV_PPWR_INTR_WATCHDOG197	bra z #intr_skip_watchdog198		st b32 D[$r0 + #time_next] $r0199		mov $r14 #proc_list_head200		call(intr_watchdog)201		ld b32 $r9 D[$r0 + #time_next]202		cmp b32 $r9 0203		bra z #intr_skip_watchdog204			nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9)205			st b32 D[$r0 + #time_prev] $r9206 207	intr_skip_watchdog:208	and $r9 $r8 NV_PPWR_INTR_SUBINTR209	bra z #intr_skip_subintr210		nv_iord($r9, NV_PPWR_SUBINTR)211		and $r10 $r9 NV_PPWR_SUBINTR_FIFO212		bra z #intr_subintr_skip_fifo213			nv_iord($r12, NV_PPWR_FIFO_INTR)214			push $r12215			imm32($r14, PROC_HOST)216			mov $r13 KMSG_FIFO217			call(send)218			pop $r12219			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 $r9226	and $r8 $r9227	nv_iowr(NV_PPWR_INTR_ACK, $r8)228 229	pop $r8230	mov $flags $r8231	pop $r15232	pop $r14233	pop $r13234	pop $r12235	pop $r11236	pop $r10237	pop $r9238	pop $r8239	pop $r0240	bclr $flags $p0241	iret242 243// calculate the number of ticks in the specified nanoseconds delay244//245// $r15 - current246// $r14 - ns247// $r14 - ticks (return)248// $r0  - zero249ticks_from_ns:250	push $r12251	push $r11252 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 1000259 260	/* check if there wasn't any overflow */261	cmpu b32 $r11 0262	bra e #ticks_from_ns_quit263 264	/* let's divide then multiply, too bad for the precision! */265	div $r14 $r14 1000266	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 271ticks_from_ns_quit:272	mov b32 $r14 $r12273	pop $r11274	pop $r12275	ret276 277// calculate the number of ticks in the specified microsecond delay278//279// $r15 - current280// $r14 - us281// $r14 - ticks (return)282// $r0  - zero283ticks_from_us:284	push $r12285	push $r11286 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 $r12291 292	/* check if there wasn't any overflow */293	cmpu b32 $r11 0294	bra e #ticks_from_us_quit295 296	/* Overflow! */297	clear b32 $r14298 299ticks_from_us_quit:300	pop $r11301	pop $r12302	ret303 304// calculate the number of ticks in the specified microsecond delay305//306// $r15 - current307// $r14 - ticks308// $r14 - us (return)309// $r0  - zero310ticks_to_us:311	/* simply divide $ticks by HW_TICKS_PER_US */312	imm32($r13, HW_TICKS_PER_US)313	div $r14 $r14 $r13314 315	ret316 317// request the current process be sent a message after a timeout expires318//319// $r15 - current320// $r14 - ticks (make sure it is < 2^31 to avoid any possible overflow)321// $r0  - zero322timer:323	push $r9324	push $r8325 326	// interrupts off to prevent racing with timer isr327	bclr $flags ie0328 329	// if current process already has a timer set, bail330	ld b32 $r8 D[$r15 + #proc_time]331	cmp b32 $r8 0332	bra g #timer_done333 334	// halt watchdog timer temporarily335	clear b32 $r8336	nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)337 338	// find out how much time elapsed since the last update339	// of the watchdog and add this time to the wanted ticks340	nv_iord($r8, NV_PPWR_WATCHDOG_TIME)341	ld b32 $r9 D[$r0 + #time_prev]342	sub b32 $r9 $r8343	add b32 $r14 $r9344	st b32 D[$r15 + #proc_time] $r14345 346	// check for a pending interrupt.  if there's one already347	// pending, we can just bail since the timer isr will348	// queue the next soonest right after it's done349	nv_iord($r8, NV_PPWR_INTR)350	and $r8 NV_PPWR_INTR_WATCHDOG351	bra nz #timer_enable352 353	// update the watchdog if this timer should expire first,354	// or if there's no timeout already set355	nv_iord($r8, NV_PPWR_WATCHDOG_TIME)356	cmp b32 $r14 $r0357	bra e #timer_reset358	cmp b32 $r14 $r8359	bra g #timer_enable360		timer_reset:361		nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)362		st b32 D[$r0 + #time_prev] $r14363 364	// re-enable the watchdog timer365	timer_enable:366	mov $r8 1367	nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)368 369	// interrupts back on370	timer_done:371	bset $flags ie0372 373	pop $r8374	pop $r9375	ret376 377// send message to another process378//379// $r15 - current380// $r14 - process381// $r13 - message382// $r12 - message data 0383// $r11 - message data 1384// $r0  - zero385send_proc:386	push $r8387	push $r9388	// check for space in queue389	ld b32 $r8 D[$r14 + #proc_qget]390	ld b32 $r9 D[$r14 + #proc_qput]391	xor $r8 #proc_qmaskb392	cmp b32 $r8 $r9393	bra e #send_done394 395	// enqueue message396	and $r8 $r9 #proc_qmaskp397	shl b32 $r8 $r8 #proc_qlen398	add b32 $r8 #proc_queue399	add b32 $r8 $r14400 401	ld b32 $r10 D[$r15 + #proc_id]402	st b32 D[$r8 + #msg_process] $r10403	st b32 D[$r8 + #msg_message] $r13404	st b32 D[$r8 + #msg_data0] $r12405	st b32 D[$r8 + #msg_data1] $r11406 407	// increment PUT408	add b32 $r9 1409	and $r9 #proc_qmaskf410	st b32 D[$r14 + #proc_qput] $r9411	bset $flags $p2412	send_done:413	pop $r9414	pop $r8415	ret416 417// lookup process structure by its name418//419// $r15 - current420// $r14 - process name421// $r0  - zero422//423// $r14 - process424// $p1  - success425find:426	push $r8427	mov $r8 #proc_list_head428	bset $flags $p1429	find_loop:430		ld b32 $r10 D[$r8 + #proc_id]431		cmp b32 $r10 $r14432		bra e #find_done433		add b32 $r8 #proc_size434		cmp b32 $r8 #proc_list_tail435		bra ne #find_loop436		bclr $flags $p1437	find_done:438	mov b32 $r14 $r8439	pop $r8440	ret441 442// send message to another process443//444// $r15 - current445// $r14 - process id446// $r13 - message447// $r12 - message data 0448// $r11 - message data 1449// $r0  - zero450send:451	call(find)452	bra $p1 #send_proc453	ret454 455// process single message for a given process456//457// $r15 - current458// $r14 - process459// $r0  - zero460recv:461	push $r9462	push $r8463 464	ld b32 $r8 D[$r14 + #proc_qget]465	ld b32 $r9 D[$r14 + #proc_qput]466	bclr $flags $p1467	cmp b32 $r8 $r9468	bra e #recv_done469		// dequeue message470		and $r9 $r8 #proc_qmaskp471		add b32 $r8 1472		and $r8 #proc_qmaskf473		st b32 D[$r14 + #proc_qget] $r8474		ld b32 $r10 D[$r14 + #proc_recv]475 476		push $r15477		mov $r15 $flags478		push $r15479		mov b32 $r15 $r14480 481		shl b32 $r9 $r9 #proc_qlen482		add b32 $r14 $r9483		add b32 $r14 #proc_queue484		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 it490		call $r10491		pop $r15492		mov $flags $r15493		bset $flags $p1494		pop $r15495	recv_done:496	pop $r8497	pop $r9498	ret499 500init:501	// setup stack502	nv_iord($r1, NV_PPWR_CAPS)503	extr $r1 $r1 9:17504	shl b32 $r1 8505	mov $sp $r1506 507#ifdef NVKM_FALCON_MMIO_UAS508	// somehow allows the magic "access mmio via D[]" stuff that's509	// used by the nv_rd32/nv_wr32 macros to work510	imm32($r1, 0x10 | NV_PPWR_UAS_CONFIG_ENABLE)511	nv_iowrs(NV_PPWR_UAS_CONFIG, $r1)512#endif513 514	// route all interrupts except user0/1 and pause to fuc515	imm32($r1, 0xe0)516	nv_iowr(NV_PPWR_INTR_ROUTE, $r1)517 518	// enable watchdog and subintr intrs519	mov $r1 NV_PPWR_INTR_EN_CLR_MASK520	nv_iowr(NV_PPWR_INTR_EN_CLR, $r1)521	mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG522	or $r1 NV_PPWR_INTR_EN_SET_SUBINTR523	nv_iowr(NV_PPWR_INTR_EN_SET, $r1)524 525	// enable interrupts globally526	imm32($r1, #intr)527	and $r1 0xffff528	mov $iv0 $r1529	bset $flags ie0530 531	// enable watchdog timer532	mov $r1 1533	nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1)534 535	// bootstrap processes, idle process will be last, and not return536	mov $r15 #proc_list_head537	init_proc:538		ld b32 $r1 D[$r15 + #proc_init]539		cmp b32 $r1 0540		bra z #init_proc541		call $r1542		add b32 $r15 #proc_size543		bra #init_proc544#endif545