xref: /openbmc/linux/arch/arm/kernel/iwmmxt.S (revision 46eeaa11bdd1bc9e077bdf741d32ca7235d263c6)
1d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */
21da177e4SLinus Torvalds/*
31da177e4SLinus Torvalds *  linux/arch/arm/kernel/iwmmxt.S
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *  XScale iWMMXt (Concan) context switching and handling
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds *  Initial code:
81da177e4SLinus Torvalds *  Copyright (c) 2003, Intel Corporation
91da177e4SLinus Torvalds *
101da177e4SLinus Torvalds *  Full lazy switching support, optimizations and more, by Nicolas Pitre
111da177e4SLinus Torvalds*   Copyright (c) 2003-2004, MontaVista Software, Inc.
121da177e4SLinus Torvalds */
131da177e4SLinus Torvalds
141da177e4SLinus Torvalds#include <linux/linkage.h>
151da177e4SLinus Torvalds#include <asm/ptrace.h>
161da177e4SLinus Torvalds#include <asm/thread_info.h>
17e6ae744dSSam Ravnborg#include <asm/asm-offsets.h>
18431a84b1SCatalin Marinas#include <asm/assembler.h>
193c9f5708SJian Cai#include "iwmmxt.h"
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds#define MMX_WR0		 	(0x00)
221da177e4SLinus Torvalds#define MMX_WR1		 	(0x08)
231da177e4SLinus Torvalds#define MMX_WR2		 	(0x10)
241da177e4SLinus Torvalds#define MMX_WR3			(0x18)
251da177e4SLinus Torvalds#define MMX_WR4		 	(0x20)
261da177e4SLinus Torvalds#define MMX_WR5		 	(0x28)
271da177e4SLinus Torvalds#define MMX_WR6		 	(0x30)
281da177e4SLinus Torvalds#define MMX_WR7		 	(0x38)
291da177e4SLinus Torvalds#define MMX_WR8		 	(0x40)
301da177e4SLinus Torvalds#define MMX_WR9		 	(0x48)
311da177e4SLinus Torvalds#define MMX_WR10		(0x50)
321da177e4SLinus Torvalds#define MMX_WR11		(0x58)
331da177e4SLinus Torvalds#define MMX_WR12		(0x60)
341da177e4SLinus Torvalds#define MMX_WR13		(0x68)
351da177e4SLinus Torvalds#define MMX_WR14		(0x70)
361da177e4SLinus Torvalds#define MMX_WR15		(0x78)
371da177e4SLinus Torvalds#define MMX_WCSSF		(0x80)
381da177e4SLinus Torvalds#define MMX_WCASF		(0x84)
391da177e4SLinus Torvalds#define MMX_WCGR0		(0x88)
401da177e4SLinus Torvalds#define MMX_WCGR1		(0x8C)
411da177e4SLinus Torvalds#define MMX_WCGR2		(0x90)
421da177e4SLinus Torvalds#define MMX_WCGR3		(0x94)
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds#define MMX_SIZE		(0x98)
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds	.text
4713d1b957SArd Biesheuvel	.arm
481da177e4SLinus Torvalds
49303d6da1SArd BiesheuvelENTRY(iwmmxt_undef_handler)
50303d6da1SArd Biesheuvel	push		{r9, r10, lr}
51303d6da1SArd Biesheuvel	get_thread_info	r10
52303d6da1SArd Biesheuvel	mov		r9, pc
53303d6da1SArd Biesheuvel	b		iwmmxt_task_enable
54303d6da1SArd Biesheuvel	mov		r0, #0
55303d6da1SArd Biesheuvel	pop		{r9, r10, pc}
56303d6da1SArd BiesheuvelENDPROC(iwmmxt_undef_handler)
57303d6da1SArd Biesheuvel
581da177e4SLinus Torvalds/*
591da177e4SLinus Torvalds * Lazy switching of Concan coprocessor context
601da177e4SLinus Torvalds *
61303d6da1SArd Biesheuvel * r0  = struct pt_regs pointer
621da177e4SLinus Torvalds * r10 = struct thread_info pointer
631da177e4SLinus Torvalds * r9  = ret_from_exception
641da177e4SLinus Torvalds * lr  = undefined instr exit
651da177e4SLinus Torvalds *
661417a6b8SCatalin Marinas * called from prefetch exception handler with interrupts enabled
671da177e4SLinus Torvalds */
681da177e4SLinus Torvalds
691da177e4SLinus TorvaldsENTRY(iwmmxt_task_enable)
70431a84b1SCatalin Marinas	inc_preempt_count r10, r3
711da177e4SLinus Torvalds
72*66689127SArd Biesheuvel	mrc	p15, 0, r2, c15, c1, 0
73ef6c8445SHaojian Zhuang	@ CP0 and CP1 accessible?
74*66689127SArd Biesheuvel	tst	r2, #0x3
75431a84b1SCatalin Marinas	bne	4f				@ if so no business here
76ef6c8445SHaojian Zhuang	@ enable access to CP0 and CP1
77*66689127SArd Biesheuvel	orr	r2, r2, #0x3
78*66689127SArd Biesheuvel	mcr	p15, 0, r2, c15, c1, 0
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds	ldr	r3, =concan_owner
81303d6da1SArd Biesheuvel	ldr	r2, [r0, #S_PC]			@ current task pc value
821da177e4SLinus Torvalds	ldr	r1, [r3]			@ get current Concan owner
831da177e4SLinus Torvalds	sub	r2, r2, #4			@ adjust pc back
84303d6da1SArd Biesheuvel	str	r2, [r0, #S_PC]
85303d6da1SArd Biesheuvel	add	r0, r10, #TI_IWMMXT_STATE	@ get task Concan save area
86303d6da1SArd Biesheuvel	str	r0, [r3]			@ this task now owns Concan regs
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds	mrc	p15, 0, r2, c2, c0, 0
891da177e4SLinus Torvalds	mov	r2, r2				@ cpwait
908cf2389bSSebastian Hesselbarth	bl	concan_save
911da177e4SLinus Torvalds
928cf2389bSSebastian Hesselbarth#ifdef CONFIG_PREEMPT_COUNT
938cf2389bSSebastian Hesselbarth	get_thread_info r10
948cf2389bSSebastian Hesselbarth#endif
958cf2389bSSebastian Hesselbarth4:	dec_preempt_count r10, r3
9671095615SRussell King	ret	r9				@ normal exit from exception
971da177e4SLinus Torvalds
981da177e4SLinus Torvaldsconcan_save:
991da177e4SLinus Torvalds
1008cf2389bSSebastian Hesselbarth	teq	r1, #0				@ test for last ownership
1018cf2389bSSebastian Hesselbarth	beq	concan_load			@ no owner, skip save
1028cf2389bSSebastian Hesselbarth
1031da177e4SLinus Torvalds	tmrc	r2, wCon
1041da177e4SLinus Torvalds
1051da177e4SLinus Torvalds	@ CUP? wCx
1061da177e4SLinus Torvalds	tst	r2, #0x1
1071da177e4SLinus Torvalds	beq 	1f
1081da177e4SLinus Torvalds
1091da177e4SLinus Torvaldsconcan_dump:
1101da177e4SLinus Torvalds
1113c9f5708SJian Cai	wstrw	wCSSF, r1, MMX_WCSSF
1123c9f5708SJian Cai	wstrw	wCASF, r1, MMX_WCASF
1133c9f5708SJian Cai	wstrw	wCGR0, r1, MMX_WCGR0
1143c9f5708SJian Cai	wstrw	wCGR1, r1, MMX_WCGR1
1153c9f5708SJian Cai	wstrw	wCGR2, r1, MMX_WCGR2
1163c9f5708SJian Cai	wstrw	wCGR3, r1, MMX_WCGR3
1171da177e4SLinus Torvalds
1181da177e4SLinus Torvalds1:	@ MUP? wRn
1191da177e4SLinus Torvalds	tst	r2, #0x2
1201da177e4SLinus Torvalds	beq	2f
1211da177e4SLinus Torvalds
1223c9f5708SJian Cai	wstrd	wR0,  r1, MMX_WR0
1233c9f5708SJian Cai	wstrd	wR1,  r1, MMX_WR1
1243c9f5708SJian Cai	wstrd	wR2,  r1, MMX_WR2
1253c9f5708SJian Cai	wstrd	wR3,  r1, MMX_WR3
1263c9f5708SJian Cai	wstrd	wR4,  r1, MMX_WR4
1273c9f5708SJian Cai	wstrd	wR5,  r1, MMX_WR5
1283c9f5708SJian Cai	wstrd	wR6,  r1, MMX_WR6
1293c9f5708SJian Cai	wstrd	wR7,  r1, MMX_WR7
1303c9f5708SJian Cai	wstrd	wR8,  r1, MMX_WR8
1313c9f5708SJian Cai	wstrd	wR9,  r1, MMX_WR9
1323c9f5708SJian Cai	wstrd	wR10, r1, MMX_WR10
1333c9f5708SJian Cai	wstrd	wR11, r1, MMX_WR11
1343c9f5708SJian Cai	wstrd	wR12, r1, MMX_WR12
1353c9f5708SJian Cai	wstrd	wR13, r1, MMX_WR13
1363c9f5708SJian Cai	wstrd	wR14, r1, MMX_WR14
1373c9f5708SJian Cai	wstrd	wR15, r1, MMX_WR15
1381da177e4SLinus Torvalds
1391da177e4SLinus Torvalds2:	teq	r0, #0				@ anything to load?
14071095615SRussell King	reteq	lr				@ if not, return
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvaldsconcan_load:
1431da177e4SLinus Torvalds
1441da177e4SLinus Torvalds	@ Load wRn
1453c9f5708SJian Cai	wldrd	wR0,  r0, MMX_WR0
1463c9f5708SJian Cai	wldrd	wR1,  r0, MMX_WR1
1473c9f5708SJian Cai	wldrd	wR2,  r0, MMX_WR2
1483c9f5708SJian Cai	wldrd	wR3,  r0, MMX_WR3
1493c9f5708SJian Cai	wldrd	wR4,  r0, MMX_WR4
1503c9f5708SJian Cai	wldrd	wR5,  r0, MMX_WR5
1513c9f5708SJian Cai	wldrd	wR6,  r0, MMX_WR6
1523c9f5708SJian Cai	wldrd	wR7,  r0, MMX_WR7
1533c9f5708SJian Cai	wldrd	wR8,  r0, MMX_WR8
1543c9f5708SJian Cai	wldrd	wR9,  r0, MMX_WR9
1553c9f5708SJian Cai	wldrd	wR10, r0, MMX_WR10
1563c9f5708SJian Cai	wldrd	wR11, r0, MMX_WR11
1573c9f5708SJian Cai	wldrd	wR12, r0, MMX_WR12
1583c9f5708SJian Cai	wldrd	wR13, r0, MMX_WR13
1593c9f5708SJian Cai	wldrd	wR14, r0, MMX_WR14
1603c9f5708SJian Cai	wldrd	wR15, r0, MMX_WR15
1611da177e4SLinus Torvalds
1621da177e4SLinus Torvalds	@ Load wCx
1633c9f5708SJian Cai	wldrw	wCSSF, r0, MMX_WCSSF
1643c9f5708SJian Cai	wldrw	wCASF, r0, MMX_WCASF
1653c9f5708SJian Cai	wldrw	wCGR0, r0, MMX_WCGR0
1663c9f5708SJian Cai	wldrw	wCGR1, r0, MMX_WCGR1
1673c9f5708SJian Cai	wldrw	wCGR2, r0, MMX_WCGR2
1683c9f5708SJian Cai	wldrw	wCGR3, r0, MMX_WCGR3
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds	@ clear CUP/MUP (only if r1 != 0)
1711da177e4SLinus Torvalds	teq	r1, #0
1721da177e4SLinus Torvalds	mov 	r2, #0
17371095615SRussell King	reteq	lr
174431a84b1SCatalin Marinas
1758cf2389bSSebastian Hesselbarth	tmcr	wCon, r2
1766ebbf2ceSRussell King	ret	lr
1771da177e4SLinus Torvalds
17813d1b957SArd BiesheuvelENDPROC(iwmmxt_task_enable)
17913d1b957SArd Biesheuvel
1801da177e4SLinus Torvalds/*
1811da177e4SLinus Torvalds * Back up Concan regs to save area and disable access to them
1821da177e4SLinus Torvalds * (mainly for gdb or sleep mode usage)
1831da177e4SLinus Torvalds *
1841da177e4SLinus Torvalds * r0 = struct thread_info pointer of target task or NULL for any
1851da177e4SLinus Torvalds */
1861da177e4SLinus Torvalds
1871da177e4SLinus TorvaldsENTRY(iwmmxt_task_disable)
1881da177e4SLinus Torvalds
1891da177e4SLinus Torvalds	stmfd	sp!, {r4, lr}
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvalds	mrs	ip, cpsr
1921da177e4SLinus Torvalds	orr	r2, ip, #PSR_I_BIT		@ disable interrupts
1931da177e4SLinus Torvalds	msr	cpsr_c, r2
1941da177e4SLinus Torvalds
1951da177e4SLinus Torvalds	ldr	r3, =concan_owner
1961da177e4SLinus Torvalds	add	r2, r0, #TI_IWMMXT_STATE	@ get task Concan save area
1971da177e4SLinus Torvalds	ldr	r1, [r3]			@ get current Concan owner
1981da177e4SLinus Torvalds	teq	r1, #0				@ any current owner?
1991da177e4SLinus Torvalds	beq	1f				@ no: quit
2001da177e4SLinus Torvalds	teq	r0, #0				@ any owner?
2011da177e4SLinus Torvalds	teqne	r1, r2				@ or specified one?
2021da177e4SLinus Torvalds	bne	1f				@ no: quit
2031da177e4SLinus Torvalds
204ef6c8445SHaojian Zhuang	@ enable access to CP0 and CP1
205*66689127SArd Biesheuvel	mrc	p15, 0, r4, c15, c1, 0
206*66689127SArd Biesheuvel	orr	r4, r4, #0x3
207*66689127SArd Biesheuvel	mcr	p15, 0, r4, c15, c1, 0
208ef6c8445SHaojian Zhuang
2091da177e4SLinus Torvalds	mov	r0, #0				@ nothing to load
2101da177e4SLinus Torvalds	str	r0, [r3]			@ no more current owner
2111da177e4SLinus Torvalds	mrc	p15, 0, r2, c2, c0, 0
2121da177e4SLinus Torvalds	mov	r2, r2				@ cpwait
2131da177e4SLinus Torvalds	bl	concan_save
2141da177e4SLinus Torvalds
215ef6c8445SHaojian Zhuang	@ disable access to CP0 and CP1
216*66689127SArd Biesheuvel	bic	r4, r4, #0x3
217*66689127SArd Biesheuvel	mcr	p15, 0, r4, c15, c1, 0
218ef6c8445SHaojian Zhuang
2191da177e4SLinus Torvalds	mrc	p15, 0, r2, c2, c0, 0
2201da177e4SLinus Torvalds	mov	r2, r2				@ cpwait
2211da177e4SLinus Torvalds
2221da177e4SLinus Torvalds1:	msr	cpsr_c, ip			@ restore interrupt mode
2231da177e4SLinus Torvalds	ldmfd	sp!, {r4, pc}
2241da177e4SLinus Torvalds
22513d1b957SArd BiesheuvelENDPROC(iwmmxt_task_disable)
22613d1b957SArd Biesheuvel
2271da177e4SLinus Torvalds/*
2281da177e4SLinus Torvalds * Copy Concan state to given memory address
2291da177e4SLinus Torvalds *
2301da177e4SLinus Torvalds * r0 = struct thread_info pointer of target task
2311da177e4SLinus Torvalds * r1 = memory address where to store Concan state
2321da177e4SLinus Torvalds *
2331da177e4SLinus Torvalds * this is called mainly in the creation of signal stack frames
2341da177e4SLinus Torvalds */
2351da177e4SLinus Torvalds
2361da177e4SLinus TorvaldsENTRY(iwmmxt_task_copy)
2371da177e4SLinus Torvalds
2381da177e4SLinus Torvalds	mrs	ip, cpsr
2391da177e4SLinus Torvalds	orr	r2, ip, #PSR_I_BIT		@ disable interrupts
2401da177e4SLinus Torvalds	msr	cpsr_c, r2
2411da177e4SLinus Torvalds
2421da177e4SLinus Torvalds	ldr	r3, =concan_owner
2431da177e4SLinus Torvalds	add	r2, r0, #TI_IWMMXT_STATE	@ get task Concan save area
2441da177e4SLinus Torvalds	ldr	r3, [r3]			@ get current Concan owner
2451da177e4SLinus Torvalds	teq	r2, r3				@ does this task own it...
2461da177e4SLinus Torvalds	beq	1f
2471da177e4SLinus Torvalds
2481da177e4SLinus Torvalds	@ current Concan values are in the task save area
2491da177e4SLinus Torvalds	msr	cpsr_c, ip			@ restore interrupt mode
2501da177e4SLinus Torvalds	mov	r0, r1
2511da177e4SLinus Torvalds	mov	r1, r2
2521da177e4SLinus Torvalds	mov	r2, #MMX_SIZE
2531da177e4SLinus Torvalds	b	memcpy
2541da177e4SLinus Torvalds
2551da177e4SLinus Torvalds1:	@ this task owns Concan regs -- grab a copy from there
2561da177e4SLinus Torvalds	mov	r0, #0				@ nothing to load
2571da177e4SLinus Torvalds	mov	r2, #3				@ save all regs
2581da177e4SLinus Torvalds	mov	r3, lr				@ preserve return address
2591da177e4SLinus Torvalds	bl	concan_dump
2601da177e4SLinus Torvalds	msr	cpsr_c, ip			@ restore interrupt mode
2616ebbf2ceSRussell King	ret	r3
2621da177e4SLinus Torvalds
26313d1b957SArd BiesheuvelENDPROC(iwmmxt_task_copy)
26413d1b957SArd Biesheuvel
2651da177e4SLinus Torvalds/*
2661da177e4SLinus Torvalds * Restore Concan state from given memory address
2671da177e4SLinus Torvalds *
2681da177e4SLinus Torvalds * r0 = struct thread_info pointer of target task
2691da177e4SLinus Torvalds * r1 = memory address where to get Concan state from
2701da177e4SLinus Torvalds *
2711da177e4SLinus Torvalds * this is used to restore Concan state when unwinding a signal stack frame
2721da177e4SLinus Torvalds */
2731da177e4SLinus Torvalds
2741da177e4SLinus TorvaldsENTRY(iwmmxt_task_restore)
2751da177e4SLinus Torvalds
2761da177e4SLinus Torvalds	mrs	ip, cpsr
2771da177e4SLinus Torvalds	orr	r2, ip, #PSR_I_BIT		@ disable interrupts
2781da177e4SLinus Torvalds	msr	cpsr_c, r2
2791da177e4SLinus Torvalds
2801da177e4SLinus Torvalds	ldr	r3, =concan_owner
2811da177e4SLinus Torvalds	add	r2, r0, #TI_IWMMXT_STATE	@ get task Concan save area
2821da177e4SLinus Torvalds	ldr	r3, [r3]			@ get current Concan owner
2831da177e4SLinus Torvalds	bic	r2, r2, #0x7			@ 64-bit alignment
2841da177e4SLinus Torvalds	teq	r2, r3				@ does this task own it...
2851da177e4SLinus Torvalds	beq	1f
2861da177e4SLinus Torvalds
2871da177e4SLinus Torvalds	@ this task doesn't own Concan regs -- use its save area
2881da177e4SLinus Torvalds	msr	cpsr_c, ip			@ restore interrupt mode
2891da177e4SLinus Torvalds	mov	r0, r2
2901da177e4SLinus Torvalds	mov	r2, #MMX_SIZE
2911da177e4SLinus Torvalds	b	memcpy
2921da177e4SLinus Torvalds
2931da177e4SLinus Torvalds1:	@ this task owns Concan regs -- load them directly
2941da177e4SLinus Torvalds	mov	r0, r1
2951da177e4SLinus Torvalds	mov	r1, #0				@ don't clear CUP/MUP
2961da177e4SLinus Torvalds	mov	r3, lr				@ preserve return address
2971da177e4SLinus Torvalds	bl	concan_load
2981da177e4SLinus Torvalds	msr	cpsr_c, ip			@ restore interrupt mode
2996ebbf2ceSRussell King	ret	r3
3001da177e4SLinus Torvalds
30113d1b957SArd BiesheuvelENDPROC(iwmmxt_task_restore)
30213d1b957SArd Biesheuvel
3031da177e4SLinus Torvalds/*
3041da177e4SLinus Torvalds * Concan handling on task switch
3051da177e4SLinus Torvalds *
306ae95bfbbSLennert Buytenhek * r0 = next thread_info pointer
3071da177e4SLinus Torvalds *
308ae95bfbbSLennert Buytenhek * Called only from the iwmmxt notifier with task preemption disabled.
3091da177e4SLinus Torvalds */
3101da177e4SLinus TorvaldsENTRY(iwmmxt_task_switch)
3111da177e4SLinus Torvalds
312*66689127SArd Biesheuvel	mrc	p15, 0, r1, c15, c1, 0
313ef6c8445SHaojian Zhuang	@ CP0 and CP1 accessible?
314*66689127SArd Biesheuvel	tst	r1, #0x3
3151da177e4SLinus Torvalds	bne	1f				@ yes: block them for next task
3161da177e4SLinus Torvalds
317ae95bfbbSLennert Buytenhek	ldr	r2, =concan_owner
318ae95bfbbSLennert Buytenhek	add	r3, r0, #TI_IWMMXT_STATE	@ get next task Concan save area
319ae95bfbbSLennert Buytenhek	ldr	r2, [r2]			@ get current Concan owner
320ae95bfbbSLennert Buytenhek	teq	r2, r3				@ next task owns it?
3216ebbf2ceSRussell King	retne	lr				@ no: leave Concan disabled
3221da177e4SLinus Torvalds
323392ba787SLennert Buytenhek1:	@ flip Concan access
324*66689127SArd Biesheuvel	eor	r1, r1, #0x3
325*66689127SArd Biesheuvel	mcr	p15, 0, r1, c15, c1, 0
3261da177e4SLinus Torvalds
327ae95bfbbSLennert Buytenhek	mrc	p15, 0, r1, c2, c0, 0
328ae95bfbbSLennert Buytenhek	sub	pc, lr, r1, lsr #32		@ cpwait and return
3291da177e4SLinus Torvalds
33013d1b957SArd BiesheuvelENDPROC(iwmmxt_task_switch)
33113d1b957SArd Biesheuvel
3321da177e4SLinus Torvalds/*
3331da177e4SLinus Torvalds * Remove Concan ownership of given task
3341da177e4SLinus Torvalds *
3351da177e4SLinus Torvalds * r0 = struct thread_info pointer
3361da177e4SLinus Torvalds */
3371da177e4SLinus TorvaldsENTRY(iwmmxt_task_release)
3381da177e4SLinus Torvalds
3391da177e4SLinus Torvalds	mrs	r2, cpsr
3401da177e4SLinus Torvalds	orr	ip, r2, #PSR_I_BIT		@ disable interrupts
3411da177e4SLinus Torvalds	msr	cpsr_c, ip
3421da177e4SLinus Torvalds	ldr	r3, =concan_owner
3431da177e4SLinus Torvalds	add	r0, r0, #TI_IWMMXT_STATE	@ get task Concan save area
3441da177e4SLinus Torvalds	ldr	r1, [r3]			@ get current Concan owner
3451da177e4SLinus Torvalds	eors	r0, r0, r1			@ if equal...
3461da177e4SLinus Torvalds	streq	r0, [r3]			@ then clear ownership
3471da177e4SLinus Torvalds	msr	cpsr_c, r2			@ restore interrupts
3486ebbf2ceSRussell King	ret	lr
3491da177e4SLinus Torvalds
35013d1b957SArd BiesheuvelENDPROC(iwmmxt_task_release)
35113d1b957SArd Biesheuvel
3521da177e4SLinus Torvalds	.data
3531abd3502SRussell King	.align	2
3541da177e4SLinus Torvaldsconcan_owner:
3551da177e4SLinus Torvalds	.word	0
3561da177e4SLinus Torvalds
357