LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] powerpc: POWER7 optimised memcpy using VMX and enhanced prefetch
From: Jimi Xenidis @ 2012-12-07 23:20 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: Kumar Gala, paulus, linuxppc-dev
In-Reply-To: <20120531162209.04bd9bdc@kryten>


On May 31, 2012, at 1:22 AM, Anton Blanchard <anton@samba.org> wrote:

>=20
> Implement a POWER7 optimised memcpy using VMX and enhanced prefetch
> instructions.

<<snip>>

>=20
> Index: linux-build/arch/powerpc/lib/Makefile
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- linux-build.orig/arch/powerpc/lib/Makefile	2012-05-30 =
15:27:30.000000000 +1000
> +++ linux-build/arch/powerpc/lib/Makefile	2012-05-31 =
09:12:27.574372864 +1000
> @@ -17,7 +17,8 @@ obj-$(CONFIG_HAS_IOMEM)	+=3D devres.o
> obj-$(CONFIG_PPC64)	+=3D copypage_64.o copyuser_64.o \
> 			   memcpy_64.o usercopy_64.o mem_64.o string.o \
> 			   checksum_wrappers_64.o hweight_64.o \
> -			   copyuser_power7.o string_64.o =
copypage_power7.o
> +			   copyuser_power7.o string_64.o =
copypage_power7.o \
> +			   memcpy_power7.o

Hi,
I know this is a little late, but shouldn't these power7 specific =
thingies be in "obj-$(CONFIG_PPC_BOOK3S_64)".
The reason I ask is that my compiler pukes on "dcbtst" and as I deal =
with that I wanted to point this out.

-jx


> obj-$(CONFIG_XMON)	+=3D sstep.o ldstfp.o
> obj-$(CONFIG_KPROBES)	+=3D sstep.o ldstfp.o
> obj-$(CONFIG_HAVE_HW_BREAKPOINT)	+=3D sstep.o ldstfp.o
> Index: linux-build/arch/powerpc/lib/memcpy_64.S
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- linux-build.orig/arch/powerpc/lib/memcpy_64.S	2012-05-30 =
09:39:59.000000000 +1000
> +++ linux-build/arch/powerpc/lib/memcpy_64.S	2012-05-31 =
09:12:00.093876936 +1000
> @@ -11,7 +11,11 @@
>=20
> 	.align	7
> _GLOBAL(memcpy)
> +BEGIN_FTR_SECTION
> 	std	r3,48(r1)	/* save destination pointer for return =
value */
> +FTR_SECTION_ELSE
> +	b	memcpy_power7
> +ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY)
> 	PPC_MTOCRF(0x01,r5)
> 	cmpldi	cr1,r5,16
> 	neg	r6,r3		# LS 3 bits =3D # bytes to 8-byte dest =
bdry
> Index: linux-build/arch/powerpc/lib/memcpy_power7.S
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> --- /dev/null	1970-01-01 00:00:00.000000000 +0000
> +++ linux-build/arch/powerpc/lib/memcpy_power7.S	2012-05-31 =
15:28:03.495781127 +1000
> @@ -0,0 +1,650 @@
> +/*
> + * This program is free software; you can redistribute it and/or =
modify
> + * it under the terms of the GNU General Public License as published =
by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA =
02111-1307, USA.
> + *
> + * Copyright (C) IBM Corporation, 2012
> + *
> + * Author: Anton Blanchard <anton@au.ibm.com>
> + */
> +#include <asm/ppc_asm.h>
> +
> +#define STACKFRAMESIZE	256
> +#define STK_REG(i)	(112 + ((i)-14)*8)
> +
> +_GLOBAL(memcpy_power7)
> +#ifdef CONFIG_ALTIVEC
> +	cmpldi	r5,16
> +	cmpldi	cr1,r5,4096
> +
> +	std	r3,48(r1)
> +
> +	blt	.Lshort_copy
> +	bgt	cr1,.Lvmx_copy
> +#else
> +	cmpldi	r5,16
> +
> +	std	r3,48(r1)
> +
> +	blt	.Lshort_copy
> +#endif
> +
> +.Lnonvmx_copy:
> +	/* Get the source 8B aligned */
> +	neg	r6,r4
> +	mtocrf	0x01,r6
> +	clrldi	r6,r6,(64-3)
> +
> +	bf	cr7*4+3,1f
> +	lbz	r0,0(r4)
> +	addi	r4,r4,1
> +	stb	r0,0(r3)
> +	addi	r3,r3,1
> +
> +1:	bf	cr7*4+2,2f
> +	lhz	r0,0(r4)
> +	addi	r4,r4,2
> +	sth	r0,0(r3)
> +	addi	r3,r3,2
> +
> +2:	bf	cr7*4+1,3f
> +	lwz	r0,0(r4)
> +	addi	r4,r4,4
> +	stw	r0,0(r3)
> +	addi	r3,r3,4
> +
> +3:	sub	r5,r5,r6
> +	cmpldi	r5,128
> +	blt	5f
> +
> +	mflr	r0
> +	stdu	r1,-STACKFRAMESIZE(r1)
> +	std	r14,STK_REG(r14)(r1)
> +	std	r15,STK_REG(r15)(r1)
> +	std	r16,STK_REG(r16)(r1)
> +	std	r17,STK_REG(r17)(r1)
> +	std	r18,STK_REG(r18)(r1)
> +	std	r19,STK_REG(r19)(r1)
> +	std	r20,STK_REG(r20)(r1)
> +	std	r21,STK_REG(r21)(r1)
> +	std	r22,STK_REG(r22)(r1)
> +	std	r0,STACKFRAMESIZE+16(r1)
> +
> +	srdi	r6,r5,7
> +	mtctr	r6
> +
> +	/* Now do cacheline (128B) sized loads and stores. */
> +	.align	5
> +4:
> +	ld	r0,0(r4)
> +	ld	r6,8(r4)
> +	ld	r7,16(r4)
> +	ld	r8,24(r4)
> +	ld	r9,32(r4)
> +	ld	r10,40(r4)
> +	ld	r11,48(r4)
> +	ld	r12,56(r4)
> +	ld	r14,64(r4)
> +	ld	r15,72(r4)
> +	ld	r16,80(r4)
> +	ld	r17,88(r4)
> +	ld	r18,96(r4)
> +	ld	r19,104(r4)
> +	ld	r20,112(r4)
> +	ld	r21,120(r4)
> +	addi	r4,r4,128
> +	std	r0,0(r3)
> +	std	r6,8(r3)
> +	std	r7,16(r3)
> +	std	r8,24(r3)
> +	std	r9,32(r3)
> +	std	r10,40(r3)
> +	std	r11,48(r3)
> +	std	r12,56(r3)
> +	std	r14,64(r3)
> +	std	r15,72(r3)
> +	std	r16,80(r3)
> +	std	r17,88(r3)
> +	std	r18,96(r3)
> +	std	r19,104(r3)
> +	std	r20,112(r3)
> +	std	r21,120(r3)
> +	addi	r3,r3,128
> +	bdnz	4b
> +
> +	clrldi	r5,r5,(64-7)
> +
> +	ld	r14,STK_REG(r14)(r1)
> +	ld	r15,STK_REG(r15)(r1)
> +	ld	r16,STK_REG(r16)(r1)
> +	ld	r17,STK_REG(r17)(r1)
> +	ld	r18,STK_REG(r18)(r1)
> +	ld	r19,STK_REG(r19)(r1)
> +	ld	r20,STK_REG(r20)(r1)
> +	ld	r21,STK_REG(r21)(r1)
> +	ld	r22,STK_REG(r22)(r1)
> +	addi	r1,r1,STACKFRAMESIZE
> +
> +	/* Up to 127B to go */
> +5:	srdi	r6,r5,4
> +	mtocrf	0x01,r6
> +
> +6:	bf	cr7*4+1,7f
> +	ld	r0,0(r4)
> +	ld	r6,8(r4)
> +	ld	r7,16(r4)
> +	ld	r8,24(r4)
> +	ld	r9,32(r4)
> +	ld	r10,40(r4)
> +	ld	r11,48(r4)
> +	ld	r12,56(r4)
> +	addi	r4,r4,64
> +	std	r0,0(r3)
> +	std	r6,8(r3)
> +	std	r7,16(r3)
> +	std	r8,24(r3)
> +	std	r9,32(r3)
> +	std	r10,40(r3)
> +	std	r11,48(r3)
> +	std	r12,56(r3)
> +	addi	r3,r3,64
> +
> +	/* Up to 63B to go */
> +7:	bf	cr7*4+2,8f
> +	ld	r0,0(r4)
> +	ld	r6,8(r4)
> +	ld	r7,16(r4)
> +	ld	r8,24(r4)
> +	addi	r4,r4,32
> +	std	r0,0(r3)
> +	std	r6,8(r3)
> +	std	r7,16(r3)
> +	std	r8,24(r3)
> +	addi	r3,r3,32
> +
> +	/* Up to 31B to go */
> +8:	bf	cr7*4+3,9f
> +	ld	r0,0(r4)
> +	ld	r6,8(r4)
> +	addi	r4,r4,16
> +	std	r0,0(r3)
> +	std	r6,8(r3)
> +	addi	r3,r3,16
> +
> +9:	clrldi	r5,r5,(64-4)
> +
> +	/* Up to 15B to go */
> +.Lshort_copy:
> +	mtocrf	0x01,r5
> +	bf	cr7*4+0,12f
> +	lwz	r0,0(r4)	/* Less chance of a reject with word ops =
*/
> +	lwz	r6,4(r4)
> +	addi	r4,r4,8
> +	stw	r0,0(r3)
> +	stw	r6,4(r3)
> +	addi	r3,r3,8
> +
> +12:	bf	cr7*4+1,13f
> +	lwz	r0,0(r4)
> +	addi	r4,r4,4
> +	stw	r0,0(r3)
> +	addi	r3,r3,4
> +
> +13:	bf	cr7*4+2,14f
> +	lhz	r0,0(r4)
> +	addi	r4,r4,2
> +	sth	r0,0(r3)
> +	addi	r3,r3,2
> +
> +14:	bf	cr7*4+3,15f
> +	lbz	r0,0(r4)
> +	stb	r0,0(r3)
> +
> +15:	ld	r3,48(r1)
> +	blr
> +
> +.Lunwind_stack_nonvmx_copy:
> +	addi	r1,r1,STACKFRAMESIZE
> +	b	.Lnonvmx_copy
> +
> +#ifdef CONFIG_ALTIVEC
> +.Lvmx_copy:
> +	mflr	r0
> +	std	r4,56(r1)
> +	std	r5,64(r1)
> +	std	r0,16(r1)
> +	stdu	r1,-STACKFRAMESIZE(r1)
> +	bl	.enter_vmx_copy
> +	cmpwi	r3,0
> +	ld	r0,STACKFRAMESIZE+16(r1)
> +	ld	r3,STACKFRAMESIZE+48(r1)
> +	ld	r4,STACKFRAMESIZE+56(r1)
> +	ld	r5,STACKFRAMESIZE+64(r1)
> +	mtlr	r0
> +
> +	/*
> +	 * We prefetch both the source and destination using enhanced =
touch
> +	 * instructions. We use a stream ID of 0 for the load side and
> +	 * 1 for the store side.
> +	 */
> +	clrrdi	r6,r4,7
> +	clrrdi	r9,r3,7
> +	ori	r9,r9,1		/* stream=3D1 */
> +
> +	srdi	r7,r5,7		/* length in cachelines, capped at 0x3FF =
*/
> +	cmpldi	cr1,r7,0x3FF
> +	ble	cr1,1f
> +	li	r7,0x3FF
> +1:	lis	r0,0x0E00	/* depth=3D7 */
> +	sldi	r7,r7,7
> +	or	r7,r7,r0
> +	ori	r10,r7,1	/* stream=3D1 */
> +
> +	lis	r8,0x8000	/* GO=3D1 */
> +	clrldi	r8,r8,32
> +
> +.machine push
> +.machine "power4"
> +	dcbt	r0,r6,0b01000
> +	dcbt	r0,r7,0b01010
> +	dcbtst	r0,r9,0b01000
> +	dcbtst	r0,r10,0b01010
> +	eieio
> +	dcbt	r0,r8,0b01010	/* GO */
> +.machine pop
> +
> +	beq	.Lunwind_stack_nonvmx_copy
> +
> +	/*
> +	 * If source and destination are not relatively aligned we use a
> +	 * slower permute loop.
> +	 */
> +	xor	r6,r4,r3
> +	rldicl.	r6,r6,0,(64-4)
> +	bne	.Lvmx_unaligned_copy
> +
> +	/* Get the destination 16B aligned */
> +	neg	r6,r3
> +	mtocrf	0x01,r6
> +	clrldi	r6,r6,(64-4)
> +
> +	bf	cr7*4+3,1f
> +	lbz	r0,0(r4)
> +	addi	r4,r4,1
> +	stb	r0,0(r3)
> +	addi	r3,r3,1
> +
> +1:	bf	cr7*4+2,2f
> +	lhz	r0,0(r4)
> +	addi	r4,r4,2
> +	sth	r0,0(r3)
> +	addi	r3,r3,2
> +
> +2:	bf	cr7*4+1,3f
> +	lwz	r0,0(r4)
> +	addi	r4,r4,4
> +	stw	r0,0(r3)
> +	addi	r3,r3,4
> +
> +3:	bf	cr7*4+0,4f
> +	ld	r0,0(r4)
> +	addi	r4,r4,8
> +	std	r0,0(r3)
> +	addi	r3,r3,8
> +
> +4:	sub	r5,r5,r6
> +
> +	/* Get the desination 128B aligned */
> +	neg	r6,r3
> +	srdi	r7,r6,4
> +	mtocrf	0x01,r7
> +	clrldi	r6,r6,(64-7)
> +
> +	li	r9,16
> +	li	r10,32
> +	li	r11,48
> +
> +	bf	cr7*4+3,5f
> +	lvx	vr1,r0,r4
> +	addi	r4,r4,16
> +	stvx	vr1,r0,r3
> +	addi	r3,r3,16
> +
> +5:	bf	cr7*4+2,6f
> +	lvx	vr1,r0,r4
> +	lvx	vr0,r4,r9
> +	addi	r4,r4,32
> +	stvx	vr1,r0,r3
> +	stvx	vr0,r3,r9
> +	addi	r3,r3,32
> +
> +6:	bf	cr7*4+1,7f
> +	lvx	vr3,r0,r4
> +	lvx	vr2,r4,r9
> +	lvx	vr1,r4,r10
> +	lvx	vr0,r4,r11
> +	addi	r4,r4,64
> +	stvx	vr3,r0,r3
> +	stvx	vr2,r3,r9
> +	stvx	vr1,r3,r10
> +	stvx	vr0,r3,r11
> +	addi	r3,r3,64
> +
> +7:	sub	r5,r5,r6
> +	srdi	r6,r5,7
> +
> +	std	r14,STK_REG(r14)(r1)
> +	std	r15,STK_REG(r15)(r1)
> +	std	r16,STK_REG(r16)(r1)
> +
> +	li	r12,64
> +	li	r14,80
> +	li	r15,96
> +	li	r16,112
> +
> +	mtctr	r6
> +
> +	/*
> +	 * Now do cacheline sized loads and stores. By this stage the
> +	 * cacheline stores are also cacheline aligned.
> +	 */
> +	.align	5
> +8:
> +	lvx	vr7,r0,r4
> +	lvx	vr6,r4,r9
> +	lvx	vr5,r4,r10
> +	lvx	vr4,r4,r11
> +	lvx	vr3,r4,r12
> +	lvx	vr2,r4,r14
> +	lvx	vr1,r4,r15
> +	lvx	vr0,r4,r16
> +	addi	r4,r4,128
> +	stvx	vr7,r0,r3
> +	stvx	vr6,r3,r9
> +	stvx	vr5,r3,r10
> +	stvx	vr4,r3,r11
> +	stvx	vr3,r3,r12
> +	stvx	vr2,r3,r14
> +	stvx	vr1,r3,r15
> +	stvx	vr0,r3,r16
> +	addi	r3,r3,128
> +	bdnz	8b
> +
> +	ld	r14,STK_REG(r14)(r1)
> +	ld	r15,STK_REG(r15)(r1)
> +	ld	r16,STK_REG(r16)(r1)
> +
> +	/* Up to 127B to go */
> +	clrldi	r5,r5,(64-7)
> +	srdi	r6,r5,4
> +	mtocrf	0x01,r6
> +
> +	bf	cr7*4+1,9f
> +	lvx	vr3,r0,r4
> +	lvx	vr2,r4,r9
> +	lvx	vr1,r4,r10
> +	lvx	vr0,r4,r11
> +	addi	r4,r4,64
> +	stvx	vr3,r0,r3
> +	stvx	vr2,r3,r9
> +	stvx	vr1,r3,r10
> +	stvx	vr0,r3,r11
> +	addi	r3,r3,64
> +
> +9:	bf	cr7*4+2,10f
> +	lvx	vr1,r0,r4
> +	lvx	vr0,r4,r9
> +	addi	r4,r4,32
> +	stvx	vr1,r0,r3
> +	stvx	vr0,r3,r9
> +	addi	r3,r3,32
> +
> +10:	bf	cr7*4+3,11f
> +	lvx	vr1,r0,r4
> +	addi	r4,r4,16
> +	stvx	vr1,r0,r3
> +	addi	r3,r3,16
> +
> +	/* Up to 15B to go */
> +11:	clrldi	r5,r5,(64-4)
> +	mtocrf	0x01,r5
> +	bf	cr7*4+0,12f
> +	ld	r0,0(r4)
> +	addi	r4,r4,8
> +	std	r0,0(r3)
> +	addi	r3,r3,8
> +
> +12:	bf	cr7*4+1,13f
> +	lwz	r0,0(r4)
> +	addi	r4,r4,4
> +	stw	r0,0(r3)
> +	addi	r3,r3,4
> +
> +13:	bf	cr7*4+2,14f
> +	lhz	r0,0(r4)
> +	addi	r4,r4,2
> +	sth	r0,0(r3)
> +	addi	r3,r3,2
> +
> +14:	bf	cr7*4+3,15f
> +	lbz	r0,0(r4)
> +	stb	r0,0(r3)
> +
> +15:	addi	r1,r1,STACKFRAMESIZE
> +	ld	r3,48(r1)
> +	b	.exit_vmx_copy		/* tail call optimise */
> +
> +.Lvmx_unaligned_copy:
> +	/* Get the destination 16B aligned */
> +	neg	r6,r3
> +	mtocrf	0x01,r6
> +	clrldi	r6,r6,(64-4)
> +
> +	bf	cr7*4+3,1f
> +	lbz	r0,0(r4)
> +	addi	r4,r4,1
> +	stb	r0,0(r3)
> +	addi	r3,r3,1
> +
> +1:	bf	cr7*4+2,2f
> +	lhz	r0,0(r4)
> +	addi	r4,r4,2
> +	sth	r0,0(r3)
> +	addi	r3,r3,2
> +
> +2:	bf	cr7*4+1,3f
> +	lwz	r0,0(r4)
> +	addi	r4,r4,4
> +	stw	r0,0(r3)
> +	addi	r3,r3,4
> +
> +3:	bf	cr7*4+0,4f
> +	lwz	r0,0(r4)	/* Less chance of a reject with word ops =
*/
> +	lwz	r7,4(r4)
> +	addi	r4,r4,8
> +	stw	r0,0(r3)
> +	stw	r7,4(r3)
> +	addi	r3,r3,8
> +
> +4:	sub	r5,r5,r6
> +
> +	/* Get the desination 128B aligned */
> +	neg	r6,r3
> +	srdi	r7,r6,4
> +	mtocrf	0x01,r7
> +	clrldi	r6,r6,(64-7)
> +
> +	li	r9,16
> +	li	r10,32
> +	li	r11,48
> +
> +	lvsl	vr16,0,r4	/* Setup permute control vector */
> +	lvx	vr0,0,r4
> +	addi	r4,r4,16
> +
> +	bf	cr7*4+3,5f
> +	lvx	vr1,r0,r4
> +	vperm	vr8,vr0,vr1,vr16
> +	addi	r4,r4,16
> +	stvx	vr8,r0,r3
> +	addi	r3,r3,16
> +	vor	vr0,vr1,vr1
> +
> +5:	bf	cr7*4+2,6f
> +	lvx	vr1,r0,r4
> +	vperm	vr8,vr0,vr1,vr16
> +	lvx	vr0,r4,r9
> +	vperm	vr9,vr1,vr0,vr16
> +	addi	r4,r4,32
> +	stvx	vr8,r0,r3
> +	stvx	vr9,r3,r9
> +	addi	r3,r3,32
> +
> +6:	bf	cr7*4+1,7f
> +	lvx	vr3,r0,r4
> +	vperm	vr8,vr0,vr3,vr16
> +	lvx	vr2,r4,r9
> +	vperm	vr9,vr3,vr2,vr16
> +	lvx	vr1,r4,r10
> +	vperm	vr10,vr2,vr1,vr16
> +	lvx	vr0,r4,r11
> +	vperm	vr11,vr1,vr0,vr16
> +	addi	r4,r4,64
> +	stvx	vr8,r0,r3
> +	stvx	vr9,r3,r9
> +	stvx	vr10,r3,r10
> +	stvx	vr11,r3,r11
> +	addi	r3,r3,64
> +
> +7:	sub	r5,r5,r6
> +	srdi	r6,r5,7
> +
> +	std	r14,STK_REG(r14)(r1)
> +	std	r15,STK_REG(r15)(r1)
> +	std	r16,STK_REG(r16)(r1)
> +
> +	li	r12,64
> +	li	r14,80
> +	li	r15,96
> +	li	r16,112
> +
> +	mtctr	r6
> +
> +	/*
> +	 * Now do cacheline sized loads and stores. By this stage the
> +	 * cacheline stores are also cacheline aligned.
> +	 */
> +	.align	5
> +8:
> +	lvx	vr7,r0,r4
> +	vperm	vr8,vr0,vr7,vr16
> +	lvx	vr6,r4,r9
> +	vperm	vr9,vr7,vr6,vr16
> +	lvx	vr5,r4,r10
> +	vperm	vr10,vr6,vr5,vr16
> +	lvx	vr4,r4,r11
> +	vperm	vr11,vr5,vr4,vr16
> +	lvx	vr3,r4,r12
> +	vperm	vr12,vr4,vr3,vr16
> +	lvx	vr2,r4,r14
> +	vperm	vr13,vr3,vr2,vr16
> +	lvx	vr1,r4,r15
> +	vperm	vr14,vr2,vr1,vr16
> +	lvx	vr0,r4,r16
> +	vperm	vr15,vr1,vr0,vr16
> +	addi	r4,r4,128
> +	stvx	vr8,r0,r3
> +	stvx	vr9,r3,r9
> +	stvx	vr10,r3,r10
> +	stvx	vr11,r3,r11
> +	stvx	vr12,r3,r12
> +	stvx	vr13,r3,r14
> +	stvx	vr14,r3,r15
> +	stvx	vr15,r3,r16
> +	addi	r3,r3,128
> +	bdnz	8b
> +
> +	ld	r14,STK_REG(r14)(r1)
> +	ld	r15,STK_REG(r15)(r1)
> +	ld	r16,STK_REG(r16)(r1)
> +
> +	/* Up to 127B to go */
> +	clrldi	r5,r5,(64-7)
> +	srdi	r6,r5,4
> +	mtocrf	0x01,r6
> +
> +	bf	cr7*4+1,9f
> +	lvx	vr3,r0,r4
> +	vperm	vr8,vr0,vr3,vr16
> +	lvx	vr2,r4,r9
> +	vperm	vr9,vr3,vr2,vr16
> +	lvx	vr1,r4,r10
> +	vperm	vr10,vr2,vr1,vr16
> +	lvx	vr0,r4,r11
> +	vperm	vr11,vr1,vr0,vr16
> +	addi	r4,r4,64
> +	stvx	vr8,r0,r3
> +	stvx	vr9,r3,r9
> +	stvx	vr10,r3,r10
> +	stvx	vr11,r3,r11
> +	addi	r3,r3,64
> +
> +9:	bf	cr7*4+2,10f
> +	lvx	vr1,r0,r4
> +	vperm	vr8,vr0,vr1,vr16
> +	lvx	vr0,r4,r9
> +	vperm	vr9,vr1,vr0,vr16
> +	addi	r4,r4,32
> +	stvx	vr8,r0,r3
> +	stvx	vr9,r3,r9
> +	addi	r3,r3,32
> +
> +10:	bf	cr7*4+3,11f
> +	lvx	vr1,r0,r4
> +	vperm	vr8,vr0,vr1,vr16
> +	addi	r4,r4,16
> +	stvx	vr8,r0,r3
> +	addi	r3,r3,16
> +
> +	/* Up to 15B to go */
> +11:	clrldi	r5,r5,(64-4)
> +	addi	r4,r4,-16	/* Unwind the +16 load offset */
> +	mtocrf	0x01,r5
> +	bf	cr7*4+0,12f
> +	lwz	r0,0(r4)	/* Less chance of a reject with word ops =
*/
> +	lwz	r6,4(r4)
> +	addi	r4,r4,8
> +	stw	r0,0(r3)
> +	stw	r6,4(r3)
> +	addi	r3,r3,8
> +
> +12:	bf	cr7*4+1,13f
> +	lwz	r0,0(r4)
> +	addi	r4,r4,4
> +	stw	r0,0(r3)
> +	addi	r3,r3,4
> +
> +13:	bf	cr7*4+2,14f
> +	lhz	r0,0(r4)
> +	addi	r4,r4,2
> +	sth	r0,0(r3)
> +	addi	r3,r3,2
> +
> +14:	bf	cr7*4+3,15f
> +	lbz	r0,0(r4)
> +	stb	r0,0(r3)
> +
> +15:	addi	r1,r1,STACKFRAMESIZE
> +	ld	r3,48(r1)
> +	b	.exit_vmx_copy		/* tail call optimise */
> +#endif /* CONFiG_ALTIVEC */
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev

^ permalink raw reply

* Re: [linuxppc-release][PATCH] powerpc/pci-hotplug: fix init issue of rescanned pci device
From: Bjorn Helgaas @ 2012-12-07 21:15 UTC (permalink / raw)
  To: Chen Yuanquan-B41889
  Cc: 松本博郎, linux-pci, r61911, linuxppc-dev
In-Reply-To: <50C08048.3050305@freescale.com>

On Thu, Dec 6, 2012 at 4:23 AM, Chen Yuanquan-B41889
<B41889@freescale.com> wrote:
> On 12/06/2012 05:30 AM, Bjorn Helgaas wrote:
>>
>> On Wed, Dec 5, 2012 at 2:29 AM, Chen Yuanquan-B41889
>> <B41889@freescale.com> wrote:
>>>
>>> On 12/05/2012 04:26 PM, Benjamin Herrenschmidt wrote:
>>>>
>>>> On Wed, 2012-12-05 at 16:20 +0800, Chen Yuanquan-B41889 wrote:
>>>>>
>>>>> On 12/05/2012 03:17 PM, Benjamin Herrenschmidt wrote:
>>>>>>
>>>>>> On Wed, 2012-12-05 at 10:31 +0800, Yuanquan Chen wrote:
>>>>>>>
>>>>>>> On powerpc arch, some fixup work of PCI/PCI-e device is just done
>>>>>>> during the
>>>>>>> first scan at booting time. For the PCI/PCI-e device rescanned after
>>>>>>> linux OS
>>>>>>> booting up, the fixup work won't be done, which leads to dma_set_mask
>>>>>>> error or
>>>>>>> irq related issue in rescanned PCI/PCI-e device's driver. So, it does
>>>>>>> the same
>>>>>>> fixup work for the rescanned device to avoid this issue.
>>>>>>
>>>>>> Hrm, the patch is a bit gross. First the code shouldn't be copy/pasted
>>>>>> that way but factored out.
>>>>
>>>> Please, at least format your email properly so I can try to undertand
>>>> without needing aspirin.
>>>>
>>>>> There's a judgement "if (!bus->is_added)" before calling of
>>>>> pcibios_fixup_bus in pci_scan_child_bus, so for the rescanned device,
>>>>> the fixup won't execute, which leads to fatal error in driver of
>>>>> rescanned
>>>>> device on freescale  powerpc, no this issues on x86 arch.
>>>>
>>>> First, none of that invalidates my statement that you shouldn't
>>>> duplicate a whole block of code like this. Even if your approach is
>>>> correct (which is debated separately), at the very least you should
>>>> factor the code out into a common function between the two copies.
>>>>
>>>>> Remove the judgement, let it to do the pcibios_fixup_bus
>>>>> directly, the error won't occur for the rescanned device. But it's
>>>>> general code, not proper to change here, so copy the pcibios_fixup_bus
>>>>> work to  pcibios_enable_device.
>>>>>
>>>>>> I'm surprised also that is_added is false when pcibios_enable_device()
>>>>>> gets called ... that looks strange to me. At what point is that enable
>>>>>> happening in the hotplug sequence ?
>>>>>
>>>>> All devices are rescanned and then call the pci_enable_devices and
>>>>> pci_bus_add_devices.
>>>>
>>>> Where ? How ? What is the sequence happening ? In any case, I think if
>>>> we need a proper fixup done per-device like that after scan we ought to
>>>> create a new hook at the generic level rather than that sort of hack.
>>>>
>>> echo 1 > rescan to trigger dev_rescan_store:
>>>
>>> dev_rescan_store->pci_rescan_bus->pci_scan_child_bus,
>>> pci_assign_unassigned_bus_resources,
>>> pci_enable_bridges, pci_bus_add_devices
>>>
>>>
>>> pci_enable_bridges->pci_enable_device->__pci_enable_device_flags->do_pci_enable_device->
>>> pcibios_enable_device
>>>
>>> pci_bus_add_devices->pci_bus_add_device->"dev->is_added = 1"
>>>
>>> Yeah, it's general fixup code for every rescanned PCI/PCI-e device on
>>> powerpc at runtime. So if
>>> we want to call it in a ppc_md member, we need to wrap it as a function
>>> and
>>> assign it in every ppc_md,
>>> it isn't proper for the general code.
>>>
>>> Regards,
>>> yuanquan
>>>
>>>
>>>>> The patch code will be called by pci_enable_devices. The
>>>>> "dev->is_added"
>>>>> is set in pci_bus_add_device
>>>>> which is called by pci_bus_add_devices. So "dev->is_added" is false
>>>>> when
>>>>> checking it in pcibios_enable_device
>>>>> for the rescanned device.
>>>>
>>>> Who calls pci_enable_device() in the rescan case ? Why isn't it left to
>>>> the driver ? I don't think we can rely on that behaviour not to change.
>>>>
>>>>>> How do you trigger the rescan anyway ?
>>>>>
>>>>> Use the interface under /sys :
>>>>> echo 1 > /sys/bus/pci/devices/xxx/remove
>>>>>
>>>>> then echo 1 to the pci device which is the bus of the removed device
>>>>> echo 1 > /sys/bus/pci/devices/xxxx/rescan
>>>>> the removed device will be scanned and it's driver module will be
>>>>> loaded
>>>>> automatically.
>>>>
>>>> Yeah this code path are known to be fishy. I think the problem is at the
>>>> generic abstraction level and that's where it needs to be fixed.
>>>>
>>>> Cheers,
>>>> Ben.
>>>>
>>>>> Regards,
>>>>> yuanquan
>>>>>>
>>>>>> I think the problem needs to be solve at a higher level, I'm adding
>>>>>> linux-pci & Bjorn to the CC list.
>>>>>>
>>>>>> Cheers,
>>>>>> Ben.
>>>>>>
>>>>>>> Signed-off-by: Yuanquan Chen <B41889@freescale.com>
>>>>>>> ---
>>>>>>>     arch/powerpc/kernel/pci-common.c |   20 ++++++++++++++++++++
>>>>>>>     1 file changed, 20 insertions(+)
>>>>>>>
>>>>>>> diff --git a/arch/powerpc/kernel/pci-common.c
>>>>>>> b/arch/powerpc/kernel/pci-common.c
>>>>>>> index 7f94f76..f0fb070 100644
>>>>>>> --- a/arch/powerpc/kernel/pci-common.c
>>>>>>> +++ b/arch/powerpc/kernel/pci-common.c
>>>>>>> @@ -1496,6 +1496,26 @@ int pcibios_enable_device(struct pci_dev *dev,
>>>>>>> int mask)
>>>>>>>                  if (ppc_md.pcibios_enable_device_hook(dev))
>>>>>>>                          return -EINVAL;
>>>>>>>     +    if (!dev->is_added) {
>>>>>>> +               /*
>>>>>>> +                * Fixup NUMA node as it may not be setup yet by the
>>>>>>> generic
>>>>>>> +                * code and is needed by the DMA init
>>>>>>> +                */
>>>>>>> +               set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
>>>>>>> +
>>>>>>> +               /* Hook up default DMA ops */
>>>>>>> +               set_dma_ops(&dev->dev, pci_dma_ops);
>>>>>>> +               set_dma_offset(&dev->dev, PCI_DRAM_OFFSET);
>>>>>>> +
>>>>>>> +               /* Additional platform DMA/iommu setup */
>>>>>>> +               if (ppc_md.pci_dma_dev_setup)
>>>>>>> +                       ppc_md.pci_dma_dev_setup(dev);
>>>>>>> +
>>>>>>> +               /* Read default IRQs and fixup if necessary */
>>>>>>> +               pci_read_irq_line(dev);
>>>>>>> +               if (ppc_md.pci_irq_fixup)
>>>>>>> +                       ppc_md.pci_irq_fixup(dev);
>>>>>>> +       }
>>>>>>>          return pci_enable_resources(dev, mask);
>>>>>>>     }
>>
>> Is this the same issue Hiroo MATSUMOTO was working on earlier?
>> (http://comments.gmane.org/gmane.linux.ports.ppc.embedded/50080)
>
>
> Yeah, that's the exact problem I encountered. Please push it forward.

Well, as I mentioned, there are unresolved issues, so it's not just a
matter of applying the most recent patch.  If you're interested in
this problem and have some hardware to test, you can help by looking
into some of the things I mentioned in the message at the URL below.

>> We went round and round on those patches (partly my fault for
>> excessive bike-shedding), and then we stalled out because of an
>> ordering issue with CardBus init and an IRQ quirk.
>>
>> Here's the last status I remember:
>> http://marc.info/?l=linux-pci&m=135006501620378&w=2
>>
>> Bjorn
>>
>>
>>
>
>

^ permalink raw reply

* Re: [PATCH] vfio powerpc: enabled on powernv platform
From: Alex Williamson @ 2012-12-07 17:38 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: kvm, linux-kernel, Paul Mackerras, linuxppc-dev, David Gibson
In-Reply-To: <1354865750-8104-1-git-send-email-aik@ozlabs.ru>

On Fri, 2012-12-07 at 18:35 +1100, Alexey Kardashevskiy wrote:
> This patch initializes IOMMU groups based on the IOMMU
> configuration discovered during the PCI scan on POWERNV
> (POWER non virtualized) platform. The IOMMU groups are
> to be used later by VFIO driver (PCI pass through).
> 
> It also implements an API for mapping/unmapping pages for
> guest PCI drivers and providing DMA window properties.
> This API is going to be used later by QEMU-VFIO to handle
> h_put_tce hypercalls from the KVM guest.
> 
> Although this driver has been tested only on the POWERNV
> platform, it should work on any platform which supports
> TCE tables.
> 
> To enable VFIO on POWER, enable SPAPR_TCE_IOMMU config
> option and configure VFIO as required.
> 
> Cc: David Gibson <david@gibson.dropbear.id.au>
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
>  arch/powerpc/include/asm/iommu.h     |   10 ++
>  arch/powerpc/kernel/iommu.c          |  214 ++++++++++++++++++++++++++++++++++
>  arch/powerpc/platforms/powernv/pci.c |  134 +++++++++++++++++++++
>  drivers/iommu/Kconfig                |    8 ++
>  4 files changed, 366 insertions(+)
> 
> diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
> index cbfe678..be3b11b 100644
> --- a/arch/powerpc/include/asm/iommu.h
> +++ b/arch/powerpc/include/asm/iommu.h
> @@ -76,6 +76,9 @@ struct iommu_table {
>  	struct iommu_pool large_pool;
>  	struct iommu_pool pools[IOMMU_NR_POOLS];
>  	unsigned long *it_map;       /* A simple allocation bitmap for now */
> +#ifdef CONFIG_IOMMU_API
> +	struct iommu_group *it_group;
> +#endif
>  };
>  
>  struct scatterlist;
> @@ -147,5 +150,12 @@ static inline void iommu_restore(void)
>  }
>  #endif
>  
> +extern void iommu_reset_table(struct iommu_table *tbl, bool release);
> +extern long iommu_clear_tces(struct iommu_table *tbl, unsigned long entry,
> +		unsigned long pages);
> +extern long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
> +		uint64_t tce, enum dma_data_direction direction,
> +		unsigned long pages);
> +
>  #endif /* __KERNEL__ */
>  #endif /* _ASM_IOMMU_H */
> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
> index ff5a6ce..123431a 100644
> --- a/arch/powerpc/kernel/iommu.c
> +++ b/arch/powerpc/kernel/iommu.c
> @@ -44,6 +44,7 @@
>  #include <asm/kdump.h>
>  #include <asm/fadump.h>
>  #include <asm/vio.h>
> +#include <asm/tce.h>
>  
>  #define DBG(...)
>  
> @@ -856,3 +857,216 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
>  		free_pages((unsigned long)vaddr, get_order(size));
>  	}
>  }
> +
> +#ifdef CONFIG_IOMMU_API
> +/*
> + * SPAPR TCE API
> + */
> +
> +/*
> + * iommu_reset_table is called when it started/stopped being used
> + */
> +void iommu_reset_table(struct iommu_table *tbl, bool release)
> +{
> +	/*
> +	 * Page at 0 is marked as used in iommu_init_table,
> +	 * so here we clear it when called with release=false...
> +	 */
> +	if (!release && (tbl->it_offset == 0))
> +		clear_bit(0, tbl->it_map);

Isn't this redundant to the memset below?

> +
> +	iommu_clear_tces(tbl, tbl->it_offset, tbl->it_size);
> +
> +	memset(tbl->it_map, 0, (tbl->it_size + 7) >> 3);
> +
> +	/*
> +	 * ... or restore when release=true
> +	 */
> +	if (release && (tbl->it_offset == 0))
> +		set_bit(0, tbl->it_map);

"release" to me implies something is freed, maybe this should just be
called "restore".

> +}
> +EXPORT_SYMBOL_GPL(iommu_reset_table);
> +
> +/*
> + * Returns the number of used IOMMU pages (4K) within
> + * the same system page (4K or 64K).
> + * bitmap_weight is not used as it does not support bigendian maps.
> + * "offset" is an IOMMU page number relative to DMA window start.
> + */
> +static int syspage_weight(unsigned long *map, unsigned long offset)
> +{
> +	int ret = 0, nbits = PAGE_SIZE/IOMMU_PAGE_SIZE;
> +
> +	/* Aligns TCE entry number to system page boundary */
> +	offset &= PAGE_MASK >> IOMMU_PAGE_SHIFT;
> +
> +	/* Count used 4K pages */
> +	while (nbits) {
> +		if (test_bit(offset, map))
> +			++ret;
> +		--nbits;
> +		++offset;
> +	}
> +
> +	return ret;
> +}
> +
> +static void tce_flush(struct iommu_table *tbl)
> +{
> +	/* Flush/invalidate TLB caches if necessary */
> +	if (ppc_md.tce_flush)
> +		ppc_md.tce_flush(tbl);
> +
> +	/* Make sure updates are seen by hardware */
> +	mb();
> +}
> +
> +/*
> + * iommu_clear_tces clears tces and returned the number of system pages
> + * which it called put_page() on
> + */
> +static long clear_tces_nolock(struct iommu_table *tbl, unsigned long entry,
> +		unsigned long pages)
> +{
> +	int i, retpages = 0, clr;
> +	unsigned long oldtce, oldweight;
> +	struct page *page;
> +
> +	for (i = 0; i < pages; ++i) {

Any reason not to increment "entry" and avoid the 5 cases of "entry + i"
below?

> +		if (!test_bit(entry + i - tbl->it_offset, tbl->it_map))
> +			continue;
> +
> +		oldtce = ppc_md.tce_get(tbl, entry + i);
> +		ppc_md.tce_free(tbl, entry + i, 1);
> +
> +		oldweight = syspage_weight(tbl->it_map,
> +				entry + i - tbl->it_offset);
> +		clr = __test_and_clear_bit(entry + i - tbl->it_offset,
> +				tbl->it_map);
> +
> +		if (WARN_ON(!(oldtce & (TCE_PCI_WRITE | TCE_PCI_READ))))
> +			continue;
> +
> +		page = pfn_to_page(oldtce >> PAGE_SHIFT);
> +
> +		if (WARN_ON(!page))
> +			continue;
> +
> +		if (oldtce & TCE_PCI_WRITE)
> +			SetPageDirty(page);
> +
> +		put_page(page);
> +
> +		/* That was the last IOMMU page within the system page */
> +		if ((oldweight == 1) && clr)
> +			++retpages;
> +	}
> +
> +	return retpages;
> +}
> +
> +/*
> + * iommu_clear_tces clears tces and returned the number
> + * of released system pages
> + */
> +long iommu_clear_tces(struct iommu_table *tbl, unsigned long entry,
> +		unsigned long pages)
> +{
> +	int ret;
> +	struct iommu_pool *pool = get_pool(tbl, entry);
> +
> +	spin_lock(&(pool->lock));
> +	ret = clear_tces_nolock(tbl, entry, pages);
> +	tce_flush(tbl);
> +	spin_unlock(&(pool->lock));
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(iommu_clear_tces);
> +
> +static int put_tce(struct iommu_table *tbl, unsigned long entry,
> +		uint64_t tce, enum dma_data_direction direction)
> +{
> +	int ret;
> +	struct page *page = NULL;
> +	unsigned long kva, offset, oldweight;
> +
> +	/* Map new TCE */
> +	offset = (tce & IOMMU_PAGE_MASK) - (tce & PAGE_MASK);
> +	ret = get_user_pages_fast(tce & PAGE_MASK, 1,
> +			direction != DMA_TO_DEVICE, &page);
> +	if (ret != 1) {
> +		pr_err("tce_vfio: get_user_pages_fast failed tce=%llx ioba=%lx ret=%d\n",
> +				tce, entry << IOMMU_PAGE_SHIFT, ret);
> +		return -EFAULT;
> +	}
> +
> +	kva = (unsigned long) page_address(page);
> +	kva += offset;
> +
> +	/* tce_build receives a virtual address */
> +	ret = ppc_md.tce_build(tbl, entry, 1, kva, direction, NULL);
> +
> +	/* tce_build() only returns non-zero for transient errors */
> +	if (unlikely(ret)) {
> +		pr_err("tce_vfio: tce_put failed on tce=%llx ioba=%lx kva=%lx ret=%d\n",
> +				tce, entry << IOMMU_PAGE_SHIFT, kva, ret);
> +		put_page(page);
> +		return -EIO;
> +	}
> +
> +	/* Calculate if new system page has been locked */
> +	oldweight = syspage_weight(tbl->it_map, entry - tbl->it_offset);
> +	__set_bit(entry - tbl->it_offset, tbl->it_map);
> +
> +	return (oldweight == 0) ? 1 : 0;

It seems like there's an optimization for syspage_weight since you only
care about two cases, ie. syspage_weight_one and syspage_weight_zero.
The zero test is easy, just mask and return !! the value.  Testing
weight 1 means you don't have to find more than 2 bits set.  I won't
hold you to that optimization, just fyi.

> +}
> +
> +/*
> + * iommu_put_tces builds tces and returned the number of actually
> + * locked system pages
> + */
> +long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
> +		uint64_t tce, enum dma_data_direction direction,
> +		unsigned long pages)
> +{
> +	int i, ret = 0, retpages = 0;
> +	struct iommu_pool *pool = get_pool(tbl, entry);
> +
> +	BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
> +	BUG_ON(direction == DMA_NONE);
> +
> +	spin_lock(&(pool->lock));
> +
> +	/* Check if any is in use */
> +	for (i = 0; i < pages; ++i) {
> +		if (test_bit(entry + i - tbl->it_offset, tbl->it_map)) {

Again, seems like there's an optimization here that avoids individually
testing bits since you only care about zero or non-zero for a sequential
run.

> +			spin_unlock(&(pool->lock));
> +			return -EBUSY;
> +		}
> +	}
> +
> +	/* Put tces to the table */
> +	for (i = 0; (i < pages) && (ret >= 0); ++i, tce += IOMMU_PAGE_SIZE) {
> +		ret = put_tce(tbl, entry + i, tce, direction);
> +		if (ret == 1)
> +			++retpages;
> +	}
> +
> +	/*
> +	 * If failed, release locked pages, otherwise return the number
> +	 * of locked system pages
> +	 */
> +	if (ret < 0)
> +		clear_tces_nolock(tbl, entry, i);
> +	else
> +		ret = retpages;
> +
> +	tce_flush(tbl);
> +	spin_unlock(&(pool->lock));
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(iommu_put_tces);
> +
> +#endif /* CONFIG_IOMMU_API */
> diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
> index 05205cf..1b970bf 100644
> --- a/arch/powerpc/platforms/powernv/pci.c
> +++ b/arch/powerpc/platforms/powernv/pci.c
> @@ -20,6 +20,7 @@
>  #include <linux/irq.h>
>  #include <linux/io.h>
>  #include <linux/msi.h>
> +#include <linux/iommu.h>
>  
>  #include <asm/sections.h>
>  #include <asm/io.h>
> @@ -613,3 +614,136 @@ void __init pnv_pci_init(void)
>  	ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs;
>  #endif
>  }
> +
> +#ifdef CONFIG_IOMMU_API
> +/*
> + * IOMMU groups support required by VFIO
> + */
> +static int add_device(struct device *dev)
> +{
> +	struct iommu_table *tbl;
> +	int ret = 0;
> +
> +	if (WARN_ON(dev->iommu_group)) {
> +		pr_warn("tce_vfio: device %s is already in iommu group %d, skipping\n",
> +				dev_name(dev),
> +				iommu_group_id(dev->iommu_group));
> +		return -EBUSY;
> +	}
> +
> +	tbl = get_iommu_table_base(dev);
> +	if (!tbl) {
> +		pr_debug("tce_vfio: skipping device %s with no tbl\n",
> +				dev_name(dev));
> +		return 0;
> +	}
> +
> +	pr_debug("tce_vfio: adding %s to iommu group %d\n",
> +			dev_name(dev), iommu_group_id(tbl->it_group));
> +
> +	ret = iommu_group_add_device(tbl->it_group, dev);
> +	if (ret < 0)
> +		pr_err("tce_vfio: %s has not been added, ret=%d\n",
> +				dev_name(dev), ret);
> +
> +	return ret;
> +}
> +
> +static void del_device(struct device *dev)
> +{
> +	iommu_group_remove_device(dev);
> +}
> +
> +static int iommu_bus_notifier(struct notifier_block *nb,
> +			      unsigned long action, void *data)
> +{
> +	struct device *dev = data;
> +
> +	switch (action) {
> +	case BUS_NOTIFY_ADD_DEVICE:
> +		return add_device(dev);
> +	case BUS_NOTIFY_DEL_DEVICE:
> +		del_device(dev);
> +		return 0;
> +	default:
> +		return 0;
> +	}
> +}
> +
> +static struct notifier_block tce_iommu_bus_nb = {
> +	.notifier_call = iommu_bus_notifier,
> +};
> +
> +static void group_release(void *iommu_data)
> +{
> +	struct iommu_table *tbl = iommu_data;
> +	tbl->it_group = NULL;
> +}
> +
> +static int __init tce_iommu_init(void)
> +{
> +	struct pci_dev *pdev = NULL;
> +	struct iommu_table *tbl;
> +	struct iommu_group *grp;
> +
> +	/* Allocate and initialize IOMMU groups */
> +	for_each_pci_dev(pdev) {
> +		tbl = get_iommu_table_base(&pdev->dev);
> +		if (!tbl)
> +			continue;
> +
> +		/* Skip already initialized */
> +		if (tbl->it_group)
> +			continue;
> +
> +		grp = iommu_group_alloc();
> +		if (IS_ERR(grp)) {
> +			pr_info("tce_vfio: cannot create new IOMMU group, ret=%ld\n",
> +					PTR_ERR(grp));
> +			return PTR_ERR(grp);
> +		}
> +		tbl->it_group = grp;
> +		iommu_group_set_iommudata(grp, tbl, group_release);

BTW, groups have a name property that shows up in sysfs that can be set
with iommu_group_set_name().  IIRC, this was a feature David requested
for PEs.  It'd be nice if it was used for PEs...  Thanks,

Alex

> +	}
> +
> +	bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
> +
> +	/* Add PCI devices to VFIO groups */
> +	for_each_pci_dev(pdev)
> +		add_device(&pdev->dev);
> +
> +	return 0;
> +}
> +
> +static void __exit tce_iommu_cleanup(void)
> +{
> +	struct pci_dev *pdev = NULL;
> +	struct iommu_table *tbl;
> +	struct iommu_group *grp = NULL;
> +
> +	bus_unregister_notifier(&pci_bus_type, &tce_iommu_bus_nb);
> +
> +	/* Delete PCI devices from VFIO groups */
> +	for_each_pci_dev(pdev)
> +		del_device(&pdev->dev);
> +
> +	/* Release VFIO groups */
> +	for_each_pci_dev(pdev) {
> +		tbl = get_iommu_table_base(&pdev->dev);
> +		if (!tbl)
> +			continue;
> +		grp = tbl->it_group;
> +
> +		/* Skip (already) uninitialized */
> +		if (!grp)
> +			continue;
> +
> +		/* Do actual release, group_release() is expected to work */
> +		iommu_group_put(grp);
> +		BUG_ON(tbl->it_group);
> +	}
> +}
> +
> +module_init(tce_iommu_init);
> +module_exit(tce_iommu_cleanup);
> +#endif /* CONFIG_IOMMU_API */
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index 9f69b56..29d11dc 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -187,4 +187,12 @@ config EXYNOS_IOMMU_DEBUG
>  
>  	  Say N unless you need kernel log message for IOMMU debugging
>  
> +config SPAPR_TCE_IOMMU
> +	bool "sPAPR TCE IOMMU Support"
> +	depends on PPC_POWERNV
> +	select IOMMU_API
> +	help
> +	  Enables bits of IOMMU API required by VFIO. The iommu_ops is
> +	  still not implemented.
> +
>  endif # IOMMU_SUPPORT

^ permalink raw reply

* Re: [PATCH] vfio powerpc: implemented IOMMU driver for VFIO
From: Alex Williamson @ 2012-12-07 17:01 UTC (permalink / raw)
  To: Alexey Kardashevskiy
  Cc: kvm, linux-kernel, Paul Mackerras, linuxppc-dev, David Gibson
In-Reply-To: <1354865693-8060-1-git-send-email-aik@ozlabs.ru>

On Fri, 2012-12-07 at 18:34 +1100, Alexey Kardashevskiy wrote:
> VFIO implements platform independent stuff such as
> a PCI driver, BAR access (via read/write on a file descriptor
> or direct mapping when possible) and IRQ signaling.
> 
> The platform dependent part includes IOMMU initialization
> and handling. This patch implements an IOMMU driver for VFIO
> which does mapping/unmapping pages for the guest IO and
> provides information about DMA window (required by a POWERPC
> guest).
> 
> The counterpart in QEMU is required to support this functionality.
> 
> Cc: David Gibson <david@gibson.dropbear.id.au>
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
>  drivers/vfio/Kconfig                |    6 +
>  drivers/vfio/Makefile               |    1 +
>  drivers/vfio/vfio_iommu_spapr_tce.c |  348 +++++++++++++++++++++++++++++++++++
>  include/linux/vfio.h                |   30 +++
>  4 files changed, 385 insertions(+)
>  create mode 100644 drivers/vfio/vfio_iommu_spapr_tce.c
> 
> diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
> index 7cd5dec..b464687 100644
> --- a/drivers/vfio/Kconfig
> +++ b/drivers/vfio/Kconfig
> @@ -3,10 +3,16 @@ config VFIO_IOMMU_TYPE1
>  	depends on VFIO
>  	default n
>  
> +config VFIO_IOMMU_SPAPR_TCE
> +	tristate
> +	depends on VFIO && SPAPR_TCE_IOMMU
> +	default n
> +
>  menuconfig VFIO
>  	tristate "VFIO Non-Privileged userspace driver framework"
>  	depends on IOMMU_API
>  	select VFIO_IOMMU_TYPE1 if X86
> +	select VFIO_IOMMU_SPAPR_TCE if PPC_POWERNV
>  	help
>  	  VFIO provides a framework for secure userspace device drivers.
>  	  See Documentation/vfio.txt for more details.
> diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
> index 2398d4a..72bfabc 100644
> --- a/drivers/vfio/Makefile
> +++ b/drivers/vfio/Makefile
> @@ -1,3 +1,4 @@
>  obj-$(CONFIG_VFIO) += vfio.o
>  obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
> +obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
>  obj-$(CONFIG_VFIO_PCI) += pci/
> diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
> new file mode 100644
> index 0000000..b0f81fe
> --- /dev/null
> +++ b/drivers/vfio/vfio_iommu_spapr_tce.c
> @@ -0,0 +1,348 @@
> +/*
> + * VFIO: IOMMU DMA mapping support for TCE on POWER
> + *
> + * Copyright (C) 2012 IBM Corp.  All rights reserved.
> + *     Author: Alexey Kardashevskiy <aik@ozlabs.ru>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Derived from original vfio_iommu_type1.c:
> + * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
> + *     Author: Alex Williamson <alex.williamson@redhat.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +#include <linux/err.h>
> +#include <linux/vfio.h>
> +#include <asm/iommu.h>
> +
> +#define DRIVER_VERSION  "0.1"
> +#define DRIVER_AUTHOR   "aik@ozlabs.ru"
> +#define DRIVER_DESC     "VFIO IOMMU SPAPR TCE"
> +
> +static void tce_iommu_detach_group(void *iommu_data,
> +		struct iommu_group *iommu_group);
> +
> +/*
> + * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
> + */
> +
> +/*
> + * This code handles mapping and unmapping of user data buffers
> + * into DMA'ble space using the IOMMU
> + */
> +
> +#define NPAGE_TO_SIZE(npage)	((size_t)(npage) << PAGE_SHIFT)
> +
> +struct vwork {
> +	struct mm_struct	*mm;
> +	long			npage;
> +	struct work_struct	work;
> +};
> +
> +/* delayed decrement/increment for locked_vm */
> +static void lock_acct_bg(struct work_struct *work)
> +{
> +	struct vwork *vwork = container_of(work, struct vwork, work);
> +	struct mm_struct *mm;
> +
> +	mm = vwork->mm;
> +	down_write(&mm->mmap_sem);
> +	mm->locked_vm += vwork->npage;
> +	up_write(&mm->mmap_sem);
> +	mmput(mm);
> +	kfree(vwork);
> +}
> +
> +static void lock_acct(long npage)
> +{
> +	struct vwork *vwork;
> +	struct mm_struct *mm;
> +
> +	if (!current->mm)
> +		return; /* process exited */
> +
> +	if (down_write_trylock(&current->mm->mmap_sem)) {
> +		current->mm->locked_vm += npage;
> +		up_write(&current->mm->mmap_sem);
> +		return;
> +	}
> +
> +	/*
> +	 * Couldn't get mmap_sem lock, so must setup to update
> +	 * mm->locked_vm later. If locked_vm were atomic, we
> +	 * wouldn't need this silliness
> +	 */
> +	vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL);
> +	if (!vwork)
> +		return;
> +	mm = get_task_mm(current);
> +	if (!mm) {
> +		kfree(vwork);
> +		return;
> +	}
> +	INIT_WORK(&vwork->work, lock_acct_bg);
> +	vwork->mm = mm;
> +	vwork->npage = npage;
> +	schedule_work(&vwork->work);
> +}
> +
> +/*
> + * The container descriptor supports only a single group per container.
> + * Required by the API as the container is not supplied with the IOMMU group
> + * at the moment of initialization.
> + */
> +struct tce_container {
> +	struct mutex lock;
> +	struct iommu_table *tbl;
> +};
> +
> +static void *tce_iommu_open(unsigned long arg)
> +{
> +	struct tce_container *container;
> +
> +	if (arg != VFIO_SPAPR_TCE_IOMMU) {
> +		pr_err("tce_vfio: Wrong IOMMU type\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	container = kzalloc(sizeof(*container), GFP_KERNEL);
> +	if (!container)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mutex_init(&container->lock);
> +
> +	return container;
> +}
> +
> +static void tce_iommu_release(void *iommu_data)
> +{
> +	struct tce_container *container = iommu_data;
> +
> +	WARN_ON(container->tbl && !container->tbl->it_group);
> +	if (container->tbl && container->tbl->it_group)
> +		tce_iommu_detach_group(iommu_data, container->tbl->it_group);
> +
> +	mutex_destroy(&container->lock);
> +
> +	kfree(container);
> +}
> +
> +static long tce_iommu_ioctl(void *iommu_data,
> +				 unsigned int cmd, unsigned long arg)
> +{
> +	struct tce_container *container = iommu_data;
> +	unsigned long minsz;
> +	long ret;
> +
> +	switch (cmd) {
> +	case VFIO_CHECK_EXTENSION:
> +		return (arg == VFIO_SPAPR_TCE_IOMMU) ? 1 : 0;
> +
> + 	case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
> +		struct vfio_iommu_spapr_tce_info info;
> +		struct iommu_table *tbl = container->tbl;
> +
> +		if (WARN_ON(!tbl))
> +			return -ENXIO;
> +
> +		minsz = offsetofend(struct vfio_iommu_spapr_tce_info,
> +				dma32_window_size);
> +
> +		if (copy_from_user(&info, (void __user *)arg, minsz))
> +			return -EFAULT;
> +
> +		if (info.argsz < minsz)
> +			return -EINVAL;
> +
> +		info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT;
> +		info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT;
> +		info.flags = 0;
> +
> +		if (copy_to_user((void __user *)arg, &info, minsz))
> +			return -EFAULT;
> +
> +		return 0;
> +	}
> +	case VFIO_IOMMU_MAP_DMA: {
> +		vfio_iommu_spapr_tce_dma_map param;
> +		struct iommu_table *tbl = container->tbl;
> +		enum dma_data_direction direction;
> +		unsigned long locked, lock_limit;
> +
> +		if (WARN_ON(!tbl))
> +			return -ENXIO;
> +
> +		minsz = offsetofend(vfio_iommu_spapr_tce_dma_map, size);
> +
> +		if (copy_from_user(&param, (void __user *)arg, minsz))
> +			return -EFAULT;
> +
> +		if (param.argsz < minsz)
> +			return -EINVAL;
> +
> +		if ((param.flags & VFIO_DMA_MAP_FLAG_READ) &&
> +				(param.flags & VFIO_DMA_MAP_FLAG_WRITE))
> +			direction = DMA_BIDIRECTIONAL;
> +		else if (param.flags & VFIO_DMA_MAP_FLAG_READ)
> +			direction = DMA_TO_DEVICE;
> +		else if (param.flags & VFIO_DMA_MAP_FLAG_WRITE)
> +			direction = DMA_FROM_DEVICE;
> +		else
> +			return -EINVAL;

flags needs to be sanitized too.  Return EINVAL if any unknown bit is
set or else sloppy users may make it very difficult to make use of those
flag bits later.

> +
> +		if ((param.size & ~IOMMU_PAGE_MASK) ||
> +				(param.iova & ~IOMMU_PAGE_MASK) ||
> +				(param.vaddr & ~IOMMU_PAGE_MASK))
> +			return -EINVAL;
> +
> +		if ((param.iova + param.size) >
> +				((tbl->it_offset + tbl->it_size)
> +				<< IOMMU_PAGE_SHIFT))
> +			return -EINVAL;
> +
> +		if (param.iova < (tbl->it_offset << IOMMU_PAGE_SHIFT))
> +			return -EINVAL;
> +
> +		/* Account for locked pages */
> +		locked = current->mm->locked_vm +
> +			(param.size >> PAGE_SHIFT);

If a user were to map only IOMMU_PAGE_SIZE entries on a 64k PAGE_SIZE
system, they'd circumvent this test.

> +		lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
> +		if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
> +			pr_warn("RLIMIT_MEMLOCK (%ld) exceeded\n",
> +					rlimit(RLIMIT_MEMLOCK));
> +			return -ENOMEM;
> +		}
> +
> +		ret = iommu_put_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
> +				param.vaddr, direction,
> +				param.size >> IOMMU_PAGE_SHIFT);
> +
> +		if (ret > 0)
> +			lock_acct(ret);
> +
> +		return ret;
> +	}
> +	case VFIO_IOMMU_UNMAP_DMA: {
> +		vfio_iommu_spapr_tce_dma_unmap param;
> +		struct iommu_table *tbl = container->tbl;
> +
> +		if (WARN_ON(!tbl))
> +			return -ENXIO;
> +
> +		minsz = offsetofend(vfio_iommu_spapr_tce_dma_unmap, size);
> +
> +		if (copy_from_user(&param, (void __user *)arg, minsz))
> +			return -EFAULT;
> +
> +		if (param.argsz < minsz)
> +			return -EINVAL;
> +
> +		if ((param.size & ~IOMMU_PAGE_MASK) ||
> +				(param.iova & ~IOMMU_PAGE_MASK))
> +			return -EINVAL;
> +
> +		if ((param.iova + param.size) >
> +				((tbl->it_offset + tbl->it_size)
> +				<< IOMMU_PAGE_SHIFT))
> +			return -EINVAL;
> +
> +		if (param.iova < (tbl->it_offset << IOMMU_PAGE_SHIFT))
> +			return -EINVAL;

Sanitize flags here too.

> +
> +		ret = iommu_clear_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
> +				param.size >> IOMMU_PAGE_SHIFT);
> +
> +		if (ret > 0)
> +			lock_acct(-ret);
> +
> +		return ret;
> +	}
> +	default:
> +		pr_warn("tce_vfio: unexpected cmd %x\n", cmd);

This is unnecessary additional future maintenance.  You only support
EXTENSION, INFO, MAP, and UNMAP.  It doesn't matter what else gets added
later.

> +	}
> +
> +	return -ENOTTY;
> +}
> +
> +static int tce_iommu_attach_group(void *iommu_data,
> +		struct iommu_group *iommu_group)
> +{
> +	struct tce_container *container = iommu_data;
> +	struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
> +
> +	BUG_ON(!tbl);
> +	mutex_lock(&container->lock);
> +	pr_debug("tce_vfio: Attaching group #%u to iommu %p\n",
> +			iommu_group_id(iommu_group), iommu_group);
> +	if (container->tbl) {
> +		pr_warn("tce_vfio: Only one group per IOMMU container is allowed, existing id=%d, attaching id=%d\n",
> +				iommu_group_id(container->tbl->it_group),
> +				iommu_group_id(iommu_group));
> +		mutex_unlock(&container->lock);
> +		return -EBUSY;
> +	}
> +
> +	container->tbl = tbl;
> +	iommu_reset_table(tbl, false);
> +	mutex_unlock(&container->lock);
> +
> +	return 0;
> +}
> +
> +static void tce_iommu_detach_group(void *iommu_data,
> +		struct iommu_group *iommu_group)
> +{
> +	struct tce_container *container = iommu_data;
> +	struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
> +
> +	BUG_ON(!tbl);
> +	mutex_lock(&container->lock);
> +	if (tbl != container->tbl) {
> +		pr_warn("tce_vfio: detaching group #%u, expected group is #%u\n",
> +				iommu_group_id(iommu_group),
> +				iommu_group_id(tbl->it_group));
> +	} else {
> +
> +		pr_debug("tce_vfio: detaching group #%u from iommu %p\n",
> +				iommu_group_id(iommu_group), iommu_group);
> +
> +		container->tbl = NULL;
> +		iommu_reset_table(tbl, true);
> +	}
> +	mutex_unlock(&container->lock);
> +}
> +
> +const struct vfio_iommu_driver_ops tce_iommu_driver_ops = {
> +	.name		= "iommu-vfio-powerpc",
> +	.owner		= THIS_MODULE,
> +	.open		= tce_iommu_open,
> +	.release	= tce_iommu_release,
> +	.ioctl		= tce_iommu_ioctl,
> +	.attach_group	= tce_iommu_attach_group,
> +	.detach_group	= tce_iommu_detach_group,
> +};
> +
> +static int __init tce_iommu_init(void)
> +{
> +	return vfio_register_iommu_driver(&tce_iommu_driver_ops);
> +}
> +
> +static void __exit tce_iommu_cleanup(void)
> +{
> +	vfio_unregister_iommu_driver(&tce_iommu_driver_ops);
> +}
> +
> +module_init(tce_iommu_init);
> +module_exit(tce_iommu_cleanup);
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +
> diff --git a/include/linux/vfio.h b/include/linux/vfio.h
> index 0a4f180..23cfc79 100644
> --- a/include/linux/vfio.h
> +++ b/include/linux/vfio.h
> @@ -99,6 +99,7 @@ extern void vfio_unregister_iommu_driver(
>  /* Extensions */
>  
>  #define VFIO_TYPE1_IOMMU		1
> +#define VFIO_SPAPR_TCE_IOMMU		2
>  
>  /*
>   * The IOCTL interface is designed for extensibility by embedding the
> @@ -442,4 +443,33 @@ struct vfio_iommu_type1_dma_unmap {
>  
>  #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
>  
> +/* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */
> +
> +/*
> + * The SPAPR TCE info struct provides the information about the PCI bus
> + * address ranges available for DMA, these values are programmed into
> + * the hardware so the guest has to know that information.
> + *
> + * The DMA 32 bit window start is an absolute PCI bus address.
> + * The IOVA address passed via map/unmap ioctls are absolute PCI bus
> + * addresses too so the window works as a filter rather than an offset
> + * for IOVA addresses.
> + *
> + * At the momen the IOMMU page size is 4K.

s/momen/moment/

A flag will need to be added if other page sizes are supported, so as
defined here, it's always 4k.  Thanks,

Alex

> + */
> +struct vfio_iommu_spapr_tce_info {
> +	__u32 argsz;
> +	__u32 flags;			/* reserved for future use */
> +	__u32 dma32_window_start;	/* 32 bit window start (bytes) */
> +	__u32 dma32_window_size;	/* 32 bit window size (bytes) */
> +};
> +
> +#define VFIO_IOMMU_SPAPR_TCE_GET_INFO	_IO(VFIO_TYPE, VFIO_BASE + 12)
> +
> +/* Reuse type1 map/unmap structs as they are the same at the moment */
> +typedef struct vfio_iommu_type1_dma_map vfio_iommu_spapr_tce_dma_map;
> +typedef struct vfio_iommu_type1_dma_unmap vfio_iommu_spapr_tce_dma_unmap;
> +
> +/* ***************************************************************** */
> +
>  #endif /* VFIO_H */

^ permalink raw reply

* [PATCH 3/5] powerpc/83xx: refactor mpc8360e quirk for kmeter1
From: Holger Brunck @ 2012-12-07 15:09 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Holger Brunck, Gerlando Falauto
In-Reply-To: <1354892956-14623-1-git-send-email-holger.brunck@keymile.com>

From: Gerlando Falauto <gerlando.falauto@keymile.com>

Move the code for this quirk to a dedicated function.

Signed-off-by: Gerlando Falauto <gerlando.falauto@keymile.com>
Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
cc: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/83xx/km83xx.c |  149 +++++++++++++++++----------------
 1 files changed, 77 insertions(+), 72 deletions(-)

diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c
index cb6460c..88b1af0 100644
--- a/arch/powerpc/platforms/83xx/km83xx.c
+++ b/arch/powerpc/platforms/83xx/km83xx.c
@@ -43,6 +43,82 @@
 #include "mpc83xx.h"
 
 #define SVR_REV(svr)    (((svr) >>  0) & 0xFFFF) /* Revision field */
+
+static void quirk_mpc8360e_qe_enet10(void)
+{
+	/*
+	 * handle mpc8360E Erratum QE_ENET10:
+	 * RGMII AC values do not meet the specification
+	 */
+	uint svid = mfspr(SPRN_SVR);
+	struct	device_node *np_par;
+	struct	resource res;
+	void	__iomem *base;
+	int	ret;
+
+	np_par = of_find_node_by_name(NULL, "par_io");
+	if (np_par == NULL) {
+		pr_warn("%s couldn;t find par_io node\n", __func__);
+		return;
+	}
+	/* Map Parallel I/O ports registers */
+	ret = of_address_to_resource(np_par, 0, &res);
+	if (ret) {
+		pr_warn("%s couldn;t map par_io registers\n", __func__);
+		return;
+	}
+
+	base = ioremap(res.start, res.end - res.start + 1);
+
+	/*
+	 * set output delay adjustments to default values according
+	 * table 5 in Errata Rev. 5, 9/2011:
+	 *
+	 * write 0b01 to UCC1 bits 18:19
+	 * write 0b01 to UCC2 option 1 bits 4:5
+	 * write 0b01 to UCC2 option 2 bits 16:17
+	 */
+	clrsetbits_be32((base + 0xa8), 0x0c00f000, 0x04005000);
+
+	/*
+	 * set output delay adjustments to default values according
+	 * table 3-13 in Reference Manual Rev.3 05/2010:
+	 *
+	 * write 0b01 to UCC2 option 2 bits 16:17
+	 * write 0b0101 to UCC1 bits 20:23
+	 * write 0b0101 to UCC2 option 1 bits 24:27
+	 */
+	clrsetbits_be32((base + 0xac), 0x0000cff0, 0x00004550);
+
+	if (SVR_REV(svid) == 0x0021) {
+		/*
+		 * UCC2 option 1: write 0b1010 to bits 24:27
+		 * at address IMMRBAR+0x14AC
+		 */
+		clrsetbits_be32((base + 0xac), 0x000000f0, 0x000000a0);
+	} else if (SVR_REV(svid) == 0x0020) {
+		/*
+		 * UCC1: write 0b11 to bits 18:19
+		 * at address IMMRBAR+0x14A8
+		 */
+		setbits32((base + 0xa8), 0x00003000);
+
+		/*
+		 * UCC2 option 1: write 0b11 to bits 4:5
+		 * at address IMMRBAR+0x14A8
+		 */
+		setbits32((base + 0xa8), 0x0c000000);
+
+		/*
+		 * UCC2 option 2: write 0b11 to bits 16:17
+		 * at address IMMRBAR+0x14AC
+		 */
+		setbits32((base + 0xac), 0x0000c000);
+	}
+	iounmap(base);
+	of_node_put(np_par);
+}
+
 /* ************************************************************************
  *
  * Setup the architecture
@@ -73,80 +149,9 @@ static void __init mpc83xx_km_setup_arch(void)
 		for_each_node_by_name(np, "ucc")
 			par_io_of_config(np);
 	}
-
 	np = of_find_compatible_node(NULL, "network", "ucc_geth");
 	if (np != NULL) {
-		/*
-		 * handle mpc8360E Erratum QE_ENET10:
-		 * RGMII AC values do not meet the specification
-		 */
-		uint svid = mfspr(SPRN_SVR);
-		struct	device_node *np_par;
-		struct	resource res;
-		void	__iomem *base;
-		int	ret;
-
-		np_par = of_find_node_by_name(NULL, "par_io");
-		if (np_par == NULL) {
-			pr_warn("%s couldn;t find par_io node\n", __func__);
-			return;
-		}
-		/* Map Parallel I/O ports registers */
-		ret = of_address_to_resource(np_par, 0, &res);
-		if (ret) {
-			pr_warn("%s couldn;t map par_io registers\n", __func__);
-			return;
-		}
-
-		base = ioremap(res.start, res.end - res.start + 1);
-
-		/*
-		 * set output delay adjustments to default values according
-		 * table 5 in Errata Rev. 5, 9/2011:
-		 *
-		 * write 0b01 to UCC1 bits 18:19
-		 * write 0b01 to UCC2 option 1 bits 4:5
-		 * write 0b01 to UCC2 option 2 bits 16:17
-		 */
-		clrsetbits_be32((base + 0xa8), 0x0c00f000, 0x04005000);
-
-		/*
-		 * set output delay adjustments to default values according
-		 * table 3-13 in Reference Manual Rev.3 05/2010:
-		 *
-		 * write 0b01 to UCC2 option 2 bits 16:17
-		 * write 0b0101 to UCC1 bits 20:23
-		 * write 0b0101 to UCC2 option 1 bits 24:27
-		 */
-		clrsetbits_be32((base + 0xac), 0x0000cff0, 0x00004550);
-
-		if (SVR_REV(svid) == 0x0021) {
-			/*
-			 * UCC2 option 1: write 0b1010 to bits 24:27
-			 * at address IMMRBAR+0x14AC
-			 */
-			clrsetbits_be32((base + 0xac), 0x000000f0, 0x000000a0);
-		} else if (SVR_REV(svid) == 0x0020) {
-			/*
-			 * UCC1: write 0b11 to bits 18:19
-			 * at address IMMRBAR+0x14A8
-			 */
-			setbits32((base + 0xa8), 0x00003000);
-
-			/*
-			 * UCC2 option 1: write 0b11 to bits 4:5
-			 * at address IMMRBAR+0x14A8
-			 */
-			setbits32((base + 0xa8), 0x0c000000);
-
-			/*
-			 * UCC2 option 2: write 0b11 to bits 16:17
-			 * at address IMMRBAR+0x14AC
-			 */
-			setbits32((base + 0xac), 0x0000c000);
-		}
-		iounmap(base);
-		of_node_put(np_par);
+		quirk_mpc8360e_qe_enet10();
 		of_node_put(np);
 	}
 #endif	/* CONFIG_QUICC_ENGINE */
-- 
1.7.1

^ permalink raw reply related

* [PATCH 4/5] powerpc/83xx: apply mpc8360e quirk for kmeter1 only when par_io is present
From: Holger Brunck @ 2012-12-07 15:09 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Holger Brunck, Gerlando Falauto
In-Reply-To: <1354892956-14623-1-git-send-email-holger.brunck@keymile.com>

From: Gerlando Falauto <gerlando.falauto@keymile.com>

There is no point in applying this quirk when par_io is not present.

Signed-off-by: Gerlando Falauto <gerlando.falauto@keymile.com>
Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
cc: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/83xx/km83xx.c |   12 +++++++-----
 1 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c
index 88b1af0..bf4c447 100644
--- a/arch/powerpc/platforms/83xx/km83xx.c
+++ b/arch/powerpc/platforms/83xx/km83xx.c
@@ -148,11 +148,13 @@ static void __init mpc83xx_km_setup_arch(void)
 
 		for_each_node_by_name(np, "ucc")
 			par_io_of_config(np);
-	}
-	np = of_find_compatible_node(NULL, "network", "ucc_geth");
-	if (np != NULL) {
-		quirk_mpc8360e_qe_enet10();
-		of_node_put(np);
+
+		/* Only apply this quirk when par_io is available */
+		np = of_find_compatible_node(NULL, "network", "ucc_geth");
+		if (np != NULL) {
+			quirk_mpc8360e_qe_enet10();
+			of_node_put(np);
+		}
 	}
 #endif	/* CONFIG_QUICC_ENGINE */
 }
-- 
1.7.1

^ permalink raw reply related

* [PATCH 5/5] powerpc/83xx: update kmeter1_defconfig
From: Holger Brunck @ 2012-12-07 15:09 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Holger Brunck
In-Reply-To: <1354892956-14623-1-git-send-email-holger.brunck@keymile.com>

Synchronize this defconfig with latest kernel version.

Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
cc: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/configs/83xx/kmeter1_defconfig |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/configs/83xx/kmeter1_defconfig b/arch/powerpc/configs/83xx/kmeter1_defconfig
index a0dfef1..e12e60c 100644
--- a/arch/powerpc/configs/83xx/kmeter1_defconfig
+++ b/arch/powerpc/configs/83xx/kmeter1_defconfig
@@ -2,6 +2,8 @@ CONFIG_EXPERIMENTAL=y
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_LOG_BUF_SHIFT=14
 CONFIG_EXPERT=y
 CONFIG_SLAB=y
@@ -16,8 +18,6 @@ CONFIG_PARTITION_ADVANCED=y
 # CONFIG_PPC_PMAC is not set
 CONFIG_PPC_83xx=y
 CONFIG_KMETER1=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT=y
 # CONFIG_SECCOMP is not set
 CONFIG_NET=y
@@ -45,7 +45,6 @@ CONFIG_MTD_PHYSMAP_OF=y
 CONFIG_MTD_PHRAM=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_MTD_UBI_DEBUG=y
 CONFIG_PROC_DEVICETREE=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
@@ -76,5 +75,4 @@ CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_UBIFS_FS=y
 CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
-- 
1.7.1

^ permalink raw reply related

* [PATCH 2/5] powerpc/83xx: fix checkpatch warnings for km83xx.c
From: Holger Brunck @ 2012-12-07 15:09 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Holger Brunck
In-Reply-To: <1354892956-14623-1-git-send-email-holger.brunck@keymile.com>

Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
cc: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/83xx/km83xx.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/platforms/83xx/km83xx.c b/arch/powerpc/platforms/83xx/km83xx.c
index 89923d7..cb6460c 100644
--- a/arch/powerpc/platforms/83xx/km83xx.c
+++ b/arch/powerpc/platforms/83xx/km83xx.c
@@ -28,8 +28,8 @@
 #include <linux/of_device.h>
 
 #include <linux/atomic.h>
-#include <asm/time.h>
-#include <asm/io.h>
+#include <linux/time.h>
+#include <linux/io.h>
 #include <asm/machdep.h>
 #include <asm/ipic.h>
 #include <asm/irq.h>
@@ -88,15 +88,13 @@ static void __init mpc83xx_km_setup_arch(void)
 
 		np_par = of_find_node_by_name(NULL, "par_io");
 		if (np_par == NULL) {
-			printk(KERN_WARNING "%s couldn;t find par_io node\n",
-				__func__);
+			pr_warn("%s couldn;t find par_io node\n", __func__);
 			return;
 		}
 		/* Map Parallel I/O ports registers */
 		ret = of_address_to_resource(np_par, 0, &res);
 		if (ret) {
-			printk(KERN_WARNING "%s couldn;t map par_io registers\n",
-				__func__);
+			pr_warn("%s couldn;t map par_io registers\n", __func__);
 			return;
 		}
 
-- 
1.7.1

^ permalink raw reply related

* [PATCH 1/5] powerpc/82xx: fix checkpatch warnings for km82xx.c
From: Holger Brunck @ 2012-12-07 15:09 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Holger Brunck

Signed-off-by: Holger Brunck <holger.brunck@keymile.com>
cc: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/82xx/km82xx.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/platforms/82xx/km82xx.c b/arch/powerpc/platforms/82xx/km82xx.c
index cf964e1..058cc18 100644
--- a/arch/powerpc/platforms/82xx/km82xx.c
+++ b/arch/powerpc/platforms/82xx/km82xx.c
@@ -18,11 +18,11 @@
 #include <linux/fsl_devices.h>
 #include <linux/of_platform.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/cpm2.h>
 #include <asm/udbg.h>
 #include <asm/machdep.h>
-#include <asm/time.h>
+#include <linux/time.h>
 #include <asm/mpc8260.h>
 #include <asm/prom.h>
 
@@ -36,7 +36,7 @@ static void __init km82xx_pic_init(void)
 	struct device_node *np = of_find_compatible_node(NULL, NULL,
 							"fsl,pq2-pic");
 	if (!np) {
-		printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
+		pr_err("PIC init: can not find cpm-pic node\n");
 		return;
 	}
 
-- 
1.7.1

^ permalink raw reply related

* Re: [RFC] Add IBM Blue Gene/Q Platform
From: Andrew Tauferner @ 2012-12-07 14:31 UTC (permalink / raw)
  To: Jimi Xenidis
  Cc: Michael Neuling, Jimi Xenidis, Kumar Gala, Jay S Bryant,
	Josh Boyer, Todd Inglett, linuxppc-dev
In-Reply-To: <644E8572-68F8-4C31-AA9D-96EBC95BC37F@pobox.com>

[-- Attachment #1: Type: text/plain, Size: 9114 bytes --]

Jimi,

> > Do you actually want this upstream?  I assume no.
>
> I needed to get these long-term patches out there for the BGQ
> community for test.

To which BGQ community are you referring?  What is the motivation
for this work?

> I would very much like to get a version of these upstream.
> I expect only the QPX, kexec, and (maybe) the DCR changes to cause
> any controversy, but I've been wrong before.

Hehe.  Ben had a variety of issues with the BG/Q firmware when he
gave me some feedback a few years ago.

> I'll be making those patches soon and hope to get a lot of feedback
> from these patches.

What was the starting point for this work?  On what is it based?

> -jx
>
>
> >
> > Mikey
> >
> >>
> >> Here is a are the summary logs:
> >>
> >> $ git log --reverse linux-stable/linux-3.4.y..
> >> commit 5a8edb2bdd914597693eed299119ff4c2e6d31f2
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Fri Nov 9 09:26:00 2012 -0600
> >>
> >>    powerpc: Fix cputable #ifdef where CONFIG_PPC_A2 is used for
> CONFIG_PPC_BOOK3E_64
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit ea51920d7035c8d23801d6de46261e7d0a537dfd
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Fri Nov 9 08:58:27 2012 -0600
> >>
> >>    powerpc/book3e: Remove config for PPC_A2_DD2 since there is no
> reference to it
> >>
> >>    This must have been leftover from early DD1 days which is not
> >>    present in any current kernel code.
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 08151401a5db4ff0d441a1b7bf8ad92bd92b14c5
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Mon Nov 5 09:38:01 2012 -0600
> >>
> >>    powerpc/dcr: Some native DCR fixes
> >>
> >>    The following fixes have been made:
> >>     - dcr_read/write_native() must use the indexed version of the
> >>       m[ft]dcrx since the non-indexed version only allows a 10-bit
> >>       numerical space, but the C interface allows a full 32-bits.
> >>     - C bindings for m[ft]dcrx, and the "table" versions, should use
> >>       "unsigned long" so that they are 64/32 bit neutral.
> >>     - The "table" versions (__m[ft]cdr) should obtain the table
address
> >>       with LOAD_REG_ADDR(), this will also make it 64/32bit neutral.
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit c8320a5daaceed03992d763302020834ea8e17dd
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Mon Nov 5 09:12:00 2012 -0600
> >>
> >>    powerpc/dcr: Add 64-bit DCR access methods.
> >>
> >>    This patch adds the ability to make 64-bit Device Control Register
> >>    (DCR) accesses.
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit a763b3f8453b3bd83d7dded8c6644939863af430
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Thu Nov 29 12:49:24 2012 -0500
> >>
> >>    powerpc/boot: Add a "spin_threads" hook to platform_ops
> >>
> >>    It is useful for the boot program to arrange for all secondary cpus
> >>    and threads to enter the kernel in a "kexec" fashion.  This hook
makes
> >>    it possible.
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 391e43393380b514d4d02a42d059619542c7597b
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Thu Nov 29 13:01:23 2012 -0500
> >>
> >>    powerpc/kexec: Add kexec "hold" support for Book3e processors
> >>
> >>    This patch add two items:
> >>    1) Book3e requires that GPR4 survive the "hold" process, so we make
> >>       sure that happens.
> >>    2) Book3e has no real mode, and the hold code exploits this.  Since
> >>       these processors ares always translated, we arrange for the
kexeced
> >>       threads to enter the hold code using the normal kernel
> linear mapping.
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit f6e3c1f706cb6922349d639a74ff6c50acc8b9f8
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Wed Dec 5 13:41:25 2012 -0500
> >>
> >>    powerpc: Remove unecessary VSX symbols
> >>
> >>    The symbol THREAD_VSR0 is defined to be the same as THREAD_FPR0.
Its
> >>    presence causes build issues with more complex configurations.
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 4e817bb42ec8e3d3689877528dd97c4286a870eb
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Tue Nov 20 10:10:52 2012 -0600
> >>
> >>    Blue Gene/Q wicked optimizing compiler does not know the rfdi
> instruction yet
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 2071aa58b2f3b33d97c94e3a127f7c5d4ffaeb34
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Tue Nov 20 10:14:22 2012 -0600
> >>
> >>    Blue Gene/Q wicked optimizing compiler does not know the
> mfdcrx instruction yet
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 6e58088fabedbb2d724637b539ba180c03ed8b68
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Wed Oct 31 16:33:21 2012 -0500
> >>
> >>    powerpc/book3e: IBM Blue Gene/Q Boot
> >>
> >>    This patch specifically deals with the initial program load
> >>    environment so that a boot image (dtbImage.bgq) can be loaded by
the
> >>    BGQ management tools.  The boot code is a little odd because it has
to
> >>    deal with the following issues:
> >>     - Linux boot image wrappers are 32-bit programs
> >>     - BGQ Tools only load 64bit ELF programs
> >>     - BGQ Firmware information is typically loaded at an address > 4G
> >>     - BGQ FW information contains 64-bit ABI function pointers (which
are
> >>       actually function descriptors) to access firmware methods
> >>     - BGQ FW methods must be called in 64-bit mode
> >>
> >>    Includes code contributed from:
> >>      Andrew Tauferner <ataufer@us.ibm.com>
> >>      Todd Inglett <tinglett@us.ibm.com>
> >>      Eric Van Hensbergen <ericvh@gmail.com>
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 3bc841935eb4955ce2b2db69bff16f7928464597
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Wed Oct 31 22:36:54 2012 -0500
> >>
> >>    powerpc/book3e: IBM Blue Gene/Q Platform and SMP
> >>
> >>    This patch introduces BGQ as a platform and adds SMP functionality
> >>
> >>    Includes code contributed from:
> >>      Andrew Tauferner <ataufer@us.ibm.com>
> >>      Todd Inglett <tinglett@us.ibm.com>
> >>      Eric Van Hensbergen <ericvh@gmail.com>
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 279c0615917b959a652e81f4ad0d886e2d426d85
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Wed Dec 5 13:43:22 2012 -0500
> >>
> >>    powerpc/book3e: IBM Blue Gene/Q Quad Processing eXtention (QPX)
> >>
> >>    This enables kernel support for the QPX extention and is intended
for
> >>    processors that support it, usually an IBM Blue Gene processor.
> >>    Turning it on does not effect other processors but it does add code
> >>    and will quadruple the per thread save and restore area for the FPU
> >>    (hense the name).  If you have enabled VSX it will only double the
> >>    space.
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 6ff45170ab0463fb34d7011e08c7e47c396f0fd7
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Fri Nov 23 14:52:14 2012 -0600
> >>
> >>    powerpc/book3e: IBM Blue Gene/Q HVC Based Firmware Console
> >>
> >>    New HVC device that uses the Blue Gene Firmware methods to erad and
> >>    write to console.
> >>
> >>        Includes code contributed from:
> >>          Andrew Tauferner <ataufer@us.ibm.com>
> >>          Todd Inglett <tinglett@us.ibm.com>
> >>          Eric Van Hensbergen <ericvh@gmail.com>
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit e4ddc0c2ad8b3f0260d15d73e153095e95da84ac
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Thu Nov 29 15:52:04 2012 -0500
> >>
> >>    powerpc/book3e: IBM Blue Gene/Q PCIe and MSI
> >>
> >>    The following patch adds support for the BG/Q PCIe bridge and
> MSI interrupts.
> >>
> >>    Includes code contributed from:
> >>      Jay S. Bryant <jsbryant@us.ibm.com>
> >>      Eric Van Hensbergen <ericvh@gmail.com>
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 9fc0b6f729f7bd7e31338283640a718fa4b1693b
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Wed Dec 5 07:01:49 2012 -0500
> >>
> >>    powerpc/book3e: IBM Blue Gene/Q Character Drivers
> >>
> >>    The following patch adds support for user and administration
> >>    applications to access the BG/Q control system.
> >>
> >>    Includes code contributed from:
> >>      Jay S. Bryant <jsbryant@us.ibm.com>
> >>      Eric Van Hensbergen <ericvh@gmail.com>
> >>
> >>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
> >>
> >> commit 9df2c4dfde0ac75f8b2bfcf565f78c2b7382b031
> >> Author: Jimi Xenidis <jimix@pobox.com>
> >> Date:   Thu Dec 6 18:07:16 2012 -0500
> >>
> >>    Linux 3.4.22-BGQ-rc1
> >>
> >>
> >>
> >>
> >> _______________________________________________
> >> Linuxppc-dev mailing list
> >> Linuxppc-dev@lists.ozlabs.org
> >> https://lists.ozlabs.org/listinfo/linuxppc-dev
> >>
>

[-- Attachment #2: Type: text/html, Size: 14202 bytes --]

^ permalink raw reply

* [PATCH 04/25] ASoC: fsl: remove __dev* attributes
From: Bill Pemberton @ 2012-12-07 14:26 UTC (permalink / raw)
  To: alsa-devel; +Cc: gregkh, broonie, linuxppc-dev, lrg, Timur Tabi
In-Reply-To: <1354890397-28568-1-git-send-email-wfp5p@virginia.edu>

CONFIG_HOTPLUG is going away as an option.  As result the __dev*
markings will be going away.

Remove use of __devinit, __devexit_p, __devinitdata, __devinitconst,
and __devexit.

Signed-off-by: Bill Pemberton <wfp5p@virginia.edu>
Cc: Timur Tabi <timur@freescale.com>
Cc: linuxppc-dev@lists.ozlabs.org
---
 sound/soc/fsl/eukrea-tlv320.c       | 6 +++---
 sound/soc/fsl/fsl_dma.c             | 6 +++---
 sound/soc/fsl/fsl_ssi.c             | 2 +-
 sound/soc/fsl/imx-audmux.c          | 8 ++++----
 sound/soc/fsl/imx-mc13783.c         | 6 +++---
 sound/soc/fsl/imx-pcm-dma.c         | 6 +++---
 sound/soc/fsl/imx-pcm-fiq.c         | 6 +++---
 sound/soc/fsl/imx-sgtl5000.c        | 6 +++---
 sound/soc/fsl/imx-ssi.c             | 4 ++--
 sound/soc/fsl/mpc5200_psc_ac97.c    | 8 ++++----
 sound/soc/fsl/mpc5200_psc_i2s.c     | 8 ++++----
 sound/soc/fsl/mpc8610_hpcd.c        | 4 ++--
 sound/soc/fsl/mx27vis-aic32x4.c     | 6 +++---
 sound/soc/fsl/p1022_ds.c            | 4 ++--
 sound/soc/fsl/p1022_rdk.c           | 4 ++--
 sound/soc/fsl/pcm030-audio-fabric.c | 4 ++--
 16 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index 267d5b4..75ffdf0 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -93,7 +93,7 @@ static struct snd_soc_card eukrea_tlv320 = {
 	.num_links	= 1,
 };
 
-static int __devinit eukrea_tlv320_probe(struct platform_device *pdev)
+static int eukrea_tlv320_probe(struct platform_device *pdev)
 {
 	int ret;
 	int int_port = 0, ext_port;
@@ -142,7 +142,7 @@ static int __devinit eukrea_tlv320_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int __devexit eukrea_tlv320_remove(struct platform_device *pdev)
+static int eukrea_tlv320_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_card(&eukrea_tlv320);
 
@@ -155,7 +155,7 @@ static struct platform_driver eukrea_tlv320_driver = {
 		.owner = THIS_MODULE,
 	},
 	.probe = eukrea_tlv320_probe,
-	.remove = __devexit_p(eukrea_tlv320_remove),};
+	.remove = eukrea_tlv320_remove,};
 
 module_platform_driver(eukrea_tlv320_driver);
 
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 6feb265..9cc5c1f 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -894,7 +894,7 @@ static struct snd_pcm_ops fsl_dma_ops = {
 	.pointer	= fsl_dma_pointer,
 };
 
-static int __devinit fsl_soc_dma_probe(struct platform_device *pdev)
+static int fsl_soc_dma_probe(struct platform_device *pdev)
  {
 	struct dma_object *dma;
 	struct device_node *np = pdev->dev.of_node;
@@ -958,7 +958,7 @@ static int __devinit fsl_soc_dma_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __devexit fsl_soc_dma_remove(struct platform_device *pdev)
+static int fsl_soc_dma_remove(struct platform_device *pdev)
 {
 	struct dma_object *dma = dev_get_drvdata(&pdev->dev);
 
@@ -983,7 +983,7 @@ static struct platform_driver fsl_soc_dma_driver = {
 		.of_match_table = fsl_soc_dma_ids,
 	},
 	.probe = fsl_soc_dma_probe,
-	.remove = __devexit_p(fsl_soc_dma_remove),
+	.remove = fsl_soc_dma_remove,
 };
 
 module_platform_driver(fsl_soc_dma_driver);
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 4ed2afd..7decbd9 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -639,7 +639,7 @@ static void make_lowercase(char *s)
 	}
 }
 
-static int __devinit fsl_ssi_probe(struct platform_device *pdev)
+static int fsl_ssi_probe(struct platform_device *pdev)
 {
 	struct fsl_ssi_private *ssi_private;
 	int ret = 0;
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c
index 524ce62..251f4d9 100644
--- a/sound/soc/fsl/imx-audmux.c
+++ b/sound/soc/fsl/imx-audmux.c
@@ -162,7 +162,7 @@ static void __init audmux_debugfs_init(void)
 	}
 }
 
-static void __devexit audmux_debugfs_remove(void)
+static void audmux_debugfs_remove(void)
 {
 	debugfs_remove_recursive(audmux_debugfs_root);
 }
@@ -244,7 +244,7 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr,
 }
 EXPORT_SYMBOL_GPL(imx_audmux_v2_configure_port);
 
-static int __devinit imx_audmux_probe(struct platform_device *pdev)
+static int imx_audmux_probe(struct platform_device *pdev)
 {
 	struct resource *res;
 	struct pinctrl *pinctrl;
@@ -278,7 +278,7 @@ static int __devinit imx_audmux_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int __devexit imx_audmux_remove(struct platform_device *pdev)
+static int imx_audmux_remove(struct platform_device *pdev)
 {
 	if (audmux_type == IMX31_AUDMUX)
 		audmux_debugfs_remove();
@@ -289,7 +289,7 @@ static int __devexit imx_audmux_remove(struct platform_device *pdev)
 
 static struct platform_driver imx_audmux_driver = {
 	.probe		= imx_audmux_probe,
-	.remove		= __devexit_p(imx_audmux_remove),
+	.remove		= imx_audmux_remove,
 	.id_table	= imx_audmux_ids,
 	.driver	= {
 		.name	= DRIVER_NAME,
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c
index 549b31f..4ae30f2 100644
--- a/sound/soc/fsl/imx-mc13783.c
+++ b/sound/soc/fsl/imx-mc13783.c
@@ -98,7 +98,7 @@ static struct snd_soc_card imx_mc13783 = {
 	.num_dapm_routes = ARRAY_SIZE(imx_mc13783_routes),
 };
 
-static int __devinit imx_mc13783_probe(struct platform_device *pdev)
+static int imx_mc13783_probe(struct platform_device *pdev)
 {
 	int ret;
 
@@ -148,7 +148,7 @@ static int __devinit imx_mc13783_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int __devexit imx_mc13783_remove(struct platform_device *pdev)
+static int imx_mc13783_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_card(&imx_mc13783);
 
@@ -161,7 +161,7 @@ static struct platform_driver imx_mc13783_audio_driver = {
 		.owner = THIS_MODULE,
 	},
 	.probe = imx_mc13783_probe,
-	.remove = __devexit_p(imx_mc13783_remove)
+	.remove = imx_mc13783_remove
 };
 
 module_platform_driver(imx_mc13783_audio_driver);
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index d85929b..bf363d8 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -154,12 +154,12 @@ static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
 	.pcm_free	= imx_pcm_free,
 };
 
-static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
+static int imx_soc_platform_probe(struct platform_device *pdev)
 {
 	return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
 }
 
-static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
+static int imx_soc_platform_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_platform(&pdev->dev);
 	return 0;
@@ -171,7 +171,7 @@ static struct platform_driver imx_pcm_driver = {
 			.owner = THIS_MODULE,
 	},
 	.probe = imx_soc_platform_probe,
-	.remove = __devexit_p(imx_soc_platform_remove),
+	.remove = imx_soc_platform_remove,
 };
 
 module_platform_driver(imx_pcm_driver);
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 22c6130..713bd79 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -282,7 +282,7 @@ static struct snd_soc_platform_driver imx_soc_platform_fiq = {
 	.pcm_free	= imx_pcm_fiq_free,
 };
 
-static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
+static int imx_soc_platform_probe(struct platform_device *pdev)
 {
 	struct imx_ssi *ssi = platform_get_drvdata(pdev);
 	int ret;
@@ -316,7 +316,7 @@ failed_register:
 	return ret;
 }
 
-static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
+static int imx_soc_platform_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_platform(&pdev->dev);
 	return 0;
@@ -329,7 +329,7 @@ static struct platform_driver imx_pcm_driver = {
 	},
 
 	.probe = imx_soc_platform_probe,
-	.remove = __devexit_p(imx_soc_platform_remove),
+	.remove = imx_soc_platform_remove,
 };
 
 module_platform_driver(imx_pcm_driver);
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index 3d9b1c4..424347e 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -56,7 +56,7 @@ static const struct snd_soc_dapm_widget imx_sgtl5000_dapm_widgets[] = {
 	SND_SOC_DAPM_SPK("Ext Spk", NULL),
 };
 
-static int __devinit imx_sgtl5000_probe(struct platform_device *pdev)
+static int imx_sgtl5000_probe(struct platform_device *pdev)
 {
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *ssi_np, *codec_np;
@@ -185,7 +185,7 @@ fail:
 	return ret;
 }
 
-static int __devexit imx_sgtl5000_remove(struct platform_device *pdev)
+static int imx_sgtl5000_remove(struct platform_device *pdev)
 {
 	struct imx_sgtl5000_data *data = platform_get_drvdata(pdev);
 
@@ -211,7 +211,7 @@ static struct platform_driver imx_sgtl5000_driver = {
 		.of_match_table = imx_sgtl5000_dt_ids,
 	},
 	.probe = imx_sgtl5000_probe,
-	.remove = __devexit_p(imx_sgtl5000_remove),
+	.remove = imx_sgtl5000_remove,
 };
 module_platform_driver(imx_sgtl5000_driver);
 
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 006f7d4..2c8d89e 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -639,7 +639,7 @@ failed_clk:
 	return ret;
 }
 
-static int __devexit imx_ssi_remove(struct platform_device *pdev)
+static int imx_ssi_remove(struct platform_device *pdev)
 {
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	struct imx_ssi *ssi = platform_get_drvdata(pdev);
@@ -660,7 +660,7 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev)
 
 static struct platform_driver imx_ssi_driver = {
 	.probe = imx_ssi_probe,
-	.remove = __devexit_p(imx_ssi_remove),
+	.remove = imx_ssi_remove,
 
 	.driver = {
 		.name = "imx-ssi",
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index a313c0a..a4aec04 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -277,7 +277,7 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {
  * - Probe/remove operations
  * - OF device match table
  */
-static int __devinit psc_ac97_of_probe(struct platform_device *op)
+static int psc_ac97_of_probe(struct platform_device *op)
 {
 	int rc;
 	struct snd_ac97 ac97;
@@ -310,7 +310,7 @@ static int __devinit psc_ac97_of_probe(struct platform_device *op)
 	return 0;
 }
 
-static int __devexit psc_ac97_of_remove(struct platform_device *op)
+static int psc_ac97_of_remove(struct platform_device *op)
 {
 	mpc5200_audio_dma_destroy(op);
 	snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
@@ -318,7 +318,7 @@ static int __devexit psc_ac97_of_remove(struct platform_device *op)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id psc_ac97_match[] __devinitdata = {
+static struct of_device_id psc_ac97_match[] = {
 	{ .compatible = "fsl,mpc5200-psc-ac97", },
 	{ .compatible = "fsl,mpc5200b-psc-ac97", },
 	{}
@@ -327,7 +327,7 @@ MODULE_DEVICE_TABLE(of, psc_ac97_match);
 
 static struct platform_driver psc_ac97_driver = {
 	.probe = psc_ac97_of_probe,
-	.remove = __devexit_p(psc_ac97_of_remove),
+	.remove = psc_ac97_of_remove,
 	.driver = {
 		.name = "mpc5200-psc-ac97",
 		.owner = THIS_MODULE,
diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c
index ba1f0a6..b95b966 100644
--- a/sound/soc/fsl/mpc5200_psc_i2s.c
+++ b/sound/soc/fsl/mpc5200_psc_i2s.c
@@ -153,7 +153,7 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{
  * - Probe/remove operations
  * - OF device match table
  */
-static int __devinit psc_i2s_of_probe(struct platform_device *op)
+static int psc_i2s_of_probe(struct platform_device *op)
 {
 	int rc;
 	struct psc_dma *psc_dma;
@@ -205,7 +205,7 @@ static int __devinit psc_i2s_of_probe(struct platform_device *op)
 
 }
 
-static int __devexit psc_i2s_of_remove(struct platform_device *op)
+static int psc_i2s_of_remove(struct platform_device *op)
 {
 	mpc5200_audio_dma_destroy(op);
 	snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
@@ -213,7 +213,7 @@ static int __devexit psc_i2s_of_remove(struct platform_device *op)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id psc_i2s_match[] __devinitdata = {
+static struct of_device_id psc_i2s_match[] = {
 	{ .compatible = "fsl,mpc5200-psc-i2s", },
 	{ .compatible = "fsl,mpc5200b-psc-i2s", },
 	{}
@@ -222,7 +222,7 @@ MODULE_DEVICE_TABLE(of, psc_i2s_match);
 
 static struct platform_driver psc_i2s_driver = {
 	.probe = psc_i2s_of_probe,
-	.remove = __devexit_p(psc_i2s_of_remove),
+	.remove = psc_i2s_of_remove,
 	.driver = {
 		.name = "mpc5200-psc-i2s",
 		.owner = THIS_MODULE,
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 9ff9318..228c52e 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -368,7 +368,7 @@ error_alloc:
  *
  * This function is called when the platform device is removed.
  */
-static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)
+static int mpc8610_hpcd_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 	struct mpc8610_hpcd_data *machine_data =
@@ -382,7 +382,7 @@ static int __devexit mpc8610_hpcd_remove(struct platform_device *pdev)
 
 static struct platform_driver mpc8610_hpcd_driver = {
 	.probe = mpc8610_hpcd_probe,
-	.remove = __devexit_p(mpc8610_hpcd_remove),
+	.remove = mpc8610_hpcd_remove,
 	.driver = {
 		/* The name must match 'compatible' property in the device tree,
 		 * in lowercase letters.
diff --git a/sound/soc/fsl/mx27vis-aic32x4.c b/sound/soc/fsl/mx27vis-aic32x4.c
index 2b76877..3d10741 100644
--- a/sound/soc/fsl/mx27vis-aic32x4.c
+++ b/sound/soc/fsl/mx27vis-aic32x4.c
@@ -180,7 +180,7 @@ static struct snd_soc_card mx27vis_aic32x4 = {
 	.num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes),
 };
 
-static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev)
+static int mx27vis_aic32x4_probe(struct platform_device *pdev)
 {
 	struct snd_mx27vis_platform_data *pdata = pdev->dev.platform_data;
 	int ret;
@@ -219,7 +219,7 @@ static int __devinit mx27vis_aic32x4_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int __devexit mx27vis_aic32x4_remove(struct platform_device *pdev)
+static int mx27vis_aic32x4_remove(struct platform_device *pdev)
 {
 	snd_soc_unregister_card(&mx27vis_aic32x4);
 
@@ -232,7 +232,7 @@ static struct platform_driver mx27vis_aic32x4_audio_driver = {
 		.owner = THIS_MODULE,
 	},
 	.probe = mx27vis_aic32x4_probe,
-	.remove = __devexit_p(mx27vis_aic32x4_remove),
+	.remove = mx27vis_aic32x4_remove,
 };
 
 module_platform_driver(mx27vis_aic32x4_audio_driver);
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 144d496..ba59c23 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -376,7 +376,7 @@ error_put:
  *
  * This function is called when the platform device is removed.
  */
-static int __devexit p1022_ds_remove(struct platform_device *pdev)
+static int p1022_ds_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 	struct machine_data *mdata =
@@ -390,7 +390,7 @@ static int __devexit p1022_ds_remove(struct platform_device *pdev)
 
 static struct platform_driver p1022_ds_driver = {
 	.probe = p1022_ds_probe,
-	.remove = __devexit_p(p1022_ds_remove),
+	.remove = p1022_ds_remove,
 	.driver = {
 		/*
 		 * The name must match 'compatible' property in the device tree,
diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c
index 897e32f..f215519 100644
--- a/sound/soc/fsl/p1022_rdk.c
+++ b/sound/soc/fsl/p1022_rdk.c
@@ -326,7 +326,7 @@ error_put:
  *
  * This function is called when the platform device is removed.
  */
-static int __devexit p1022_rdk_remove(struct platform_device *pdev)
+static int p1022_rdk_remove(struct platform_device *pdev)
 {
 	struct snd_soc_card *card = platform_get_drvdata(pdev);
 	struct machine_data *mdata =
@@ -340,7 +340,7 @@ static int __devexit p1022_rdk_remove(struct platform_device *pdev)
 
 static struct platform_driver p1022_rdk_driver = {
 	.probe = p1022_rdk_probe,
-	.remove = __devexit_p(p1022_rdk_remove),
+	.remove = p1022_rdk_remove,
 	.driver = {
 		/*
 		 * The name must match 'compatible' property in the device tree,
diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c
index 4d26192..8e52c148 100644
--- a/sound/soc/fsl/pcm030-audio-fabric.c
+++ b/sound/soc/fsl/pcm030-audio-fabric.c
@@ -101,7 +101,7 @@ static int __init pcm030_fabric_probe(struct platform_device *op)
 	return ret;
 }
 
-static int __devexit pcm030_fabric_remove(struct platform_device *op)
+static int pcm030_fabric_remove(struct platform_device *op)
 {
 	struct pcm030_audio_data *pdata = platform_get_drvdata(op);
 	int ret;
@@ -120,7 +120,7 @@ MODULE_DEVICE_TABLE(of, pcm030_audio_match);
 
 static struct platform_driver pcm030_fabric_driver = {
 	.probe		= pcm030_fabric_probe,
-	.remove		= __devexit_p(pcm030_fabric_remove),
+	.remove		= pcm030_fabric_remove,
 	.driver		= {
 		.name	= DRV_NAME,
 		.owner	= THIS_MODULE,
-- 
1.8.0.1

^ permalink raw reply related

* Re: [RFC] Add IBM Blue Gene/Q Platform
From: Jimi Xenidis @ 2012-12-07 13:44 UTC (permalink / raw)
  To: Michael Neuling
  Cc: Andrew T Tauferner, Kumar Gala, Jay Bryant, Josh Boyer,
	Todd Inglett, linuxppc-dev
In-Reply-To: <22977.1354859787@neuling.org>


On Dec 6, 2012, at 11:56 PM, Michael Neuling <mikey@neuling.org> wrote:

> Jimi Xenidis <jimix@pobox.com> wrote:
>=20
>> Rather than flood the mailing list with the patches, I've arranged =
for a git repo to hold the changesets.
>> You can find the repo here:
>>  <https://github.com/jimix/linux-bgq>
>>=20
>> They are against GregKH's linux-stable.git long-term 3.4.y (y=3D22) =
branch.
>> The first 9 (6e58088f..) effect common code and the rest are BGQ =
specific.
>=20
> Do you actually want this upstream?  I assume no.

I needed to get these long-term patches out there for the BGQ community =
for test.
I would very much like to get a version of these upstream.
I expect only the QPX, kexec, and (maybe) the DCR changes to cause any =
controversy, but I've been wrong before.
I'll be making those patches soon and hope to get a lot of feedback from =
these patches.
-jx


>=20
> Mikey
>=20
>>=20
>> Here is a are the summary logs:
>>=20
>> $ git log --reverse linux-stable/linux-3.4.y..
>> commit 5a8edb2bdd914597693eed299119ff4c2e6d31f2
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Fri Nov 9 09:26:00 2012 -0600
>>=20
>>    powerpc: Fix cputable #ifdef where CONFIG_PPC_A2 is used for =
CONFIG_PPC_BOOK3E_64
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit ea51920d7035c8d23801d6de46261e7d0a537dfd
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Fri Nov 9 08:58:27 2012 -0600
>>=20
>>    powerpc/book3e: Remove config for PPC_A2_DD2 since there is no =
reference to it
>>=20
>>    This must have been leftover from early DD1 days which is not
>>    present in any current kernel code.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 08151401a5db4ff0d441a1b7bf8ad92bd92b14c5
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Mon Nov 5 09:38:01 2012 -0600
>>=20
>>    powerpc/dcr: Some native DCR fixes
>>=20
>>    The following fixes have been made:
>>     - dcr_read/write_native() must use the indexed version of the
>>       m[ft]dcrx since the non-indexed version only allows a 10-bit
>>       numerical space, but the C interface allows a full 32-bits.
>>     - C bindings for m[ft]dcrx, and the "table" versions, should use
>>       "unsigned long" so that they are 64/32 bit neutral.
>>     - The "table" versions (__m[ft]cdr) should obtain the table =
address
>>       with LOAD_REG_ADDR(), this will also make it 64/32bit neutral.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit c8320a5daaceed03992d763302020834ea8e17dd
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Mon Nov 5 09:12:00 2012 -0600
>>=20
>>    powerpc/dcr: Add 64-bit DCR access methods.
>>=20
>>    This patch adds the ability to make 64-bit Device Control Register
>>    (DCR) accesses.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit a763b3f8453b3bd83d7dded8c6644939863af430
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Thu Nov 29 12:49:24 2012 -0500
>>=20
>>    powerpc/boot: Add a "spin_threads" hook to platform_ops
>>=20
>>    It is useful for the boot program to arrange for all secondary =
cpus
>>    and threads to enter the kernel in a "kexec" fashion.  This hook =
makes
>>    it possible.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 391e43393380b514d4d02a42d059619542c7597b
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Thu Nov 29 13:01:23 2012 -0500
>>=20
>>    powerpc/kexec: Add kexec "hold" support for Book3e processors
>>=20
>>    This patch add two items:
>>    1) Book3e requires that GPR4 survive the "hold" process, so we =
make
>>       sure that happens.
>>    2) Book3e has no real mode, and the hold code exploits this.  =
Since
>>       these processors ares always translated, we arrange for the =
kexeced
>>       threads to enter the hold code using the normal kernel linear =
mapping.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit f6e3c1f706cb6922349d639a74ff6c50acc8b9f8
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Wed Dec 5 13:41:25 2012 -0500
>>=20
>>    powerpc: Remove unecessary VSX symbols
>>=20
>>    The symbol THREAD_VSR0 is defined to be the same as THREAD_FPR0.  =
Its
>>    presence causes build issues with more complex configurations.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 4e817bb42ec8e3d3689877528dd97c4286a870eb
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Tue Nov 20 10:10:52 2012 -0600
>>=20
>>    Blue Gene/Q wicked optimizing compiler does not know the rfdi =
instruction yet
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 2071aa58b2f3b33d97c94e3a127f7c5d4ffaeb34
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Tue Nov 20 10:14:22 2012 -0600
>>=20
>>    Blue Gene/Q wicked optimizing compiler does not know the mfdcrx =
instruction yet
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 6e58088fabedbb2d724637b539ba180c03ed8b68
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Wed Oct 31 16:33:21 2012 -0500
>>=20
>>    powerpc/book3e: IBM Blue Gene/Q Boot
>>=20
>>    This patch specifically deals with the initial program load
>>    environment so that a boot image (dtbImage.bgq) can be loaded by =
the
>>    BGQ management tools.  The boot code is a little odd because it =
has to
>>    deal with the following issues:
>>     - Linux boot image wrappers are 32-bit programs
>>     - BGQ Tools only load 64bit ELF programs
>>     - BGQ Firmware information is typically loaded at an address > 4G
>>     - BGQ FW information contains 64-bit ABI function pointers (which =
are
>>       actually function descriptors) to access firmware methods
>>     - BGQ FW methods must be called in 64-bit mode
>>=20
>>    Includes code contributed from:
>>      Andrew Tauferner <ataufer@us.ibm.com>
>>      Todd Inglett <tinglett@us.ibm.com>
>>      Eric Van Hensbergen <ericvh@gmail.com>
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 3bc841935eb4955ce2b2db69bff16f7928464597
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Wed Oct 31 22:36:54 2012 -0500
>>=20
>>    powerpc/book3e: IBM Blue Gene/Q Platform and SMP
>>=20
>>    This patch introduces BGQ as a platform and adds SMP functionality
>>=20
>>    Includes code contributed from:
>>      Andrew Tauferner <ataufer@us.ibm.com>
>>      Todd Inglett <tinglett@us.ibm.com>
>>      Eric Van Hensbergen <ericvh@gmail.com>
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 279c0615917b959a652e81f4ad0d886e2d426d85
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Wed Dec 5 13:43:22 2012 -0500
>>=20
>>    powerpc/book3e: IBM Blue Gene/Q Quad Processing eXtention (QPX)
>>=20
>>    This enables kernel support for the QPX extention and is intended =
for
>>    processors that support it, usually an IBM Blue Gene processor.
>>    Turning it on does not effect other processors but it does add =
code
>>    and will quadruple the per thread save and restore area for the =
FPU
>>    (hense the name).  If you have enabled VSX it will only double the
>>    space.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 6ff45170ab0463fb34d7011e08c7e47c396f0fd7
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Fri Nov 23 14:52:14 2012 -0600
>>=20
>>    powerpc/book3e: IBM Blue Gene/Q HVC Based Firmware Console
>>=20
>>    New HVC device that uses the Blue Gene Firmware methods to erad =
and
>>    write to console.
>>=20
>>        Includes code contributed from:
>>          Andrew Tauferner <ataufer@us.ibm.com>
>>          Todd Inglett <tinglett@us.ibm.com>
>>          Eric Van Hensbergen <ericvh@gmail.com>
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit e4ddc0c2ad8b3f0260d15d73e153095e95da84ac
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Thu Nov 29 15:52:04 2012 -0500
>>=20
>>    powerpc/book3e: IBM Blue Gene/Q PCIe and MSI
>>=20
>>    The following patch adds support for the BG/Q PCIe bridge and MSI =
interrupts.
>>=20
>>    Includes code contributed from:
>>      Jay S. Bryant <jsbryant@us.ibm.com>
>>      Eric Van Hensbergen <ericvh@gmail.com>
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 9fc0b6f729f7bd7e31338283640a718fa4b1693b
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Wed Dec 5 07:01:49 2012 -0500
>>=20
>>    powerpc/book3e: IBM Blue Gene/Q Character Drivers
>>=20
>>    The following patch adds support for user and administration
>>    applications to access the BG/Q control system.
>>=20
>>    Includes code contributed from:
>>      Jay S. Bryant <jsbryant@us.ibm.com>
>>      Eric Van Hensbergen <ericvh@gmail.com>
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>> commit 9df2c4dfde0ac75f8b2bfcf565f78c2b7382b031
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Thu Dec 6 18:07:16 2012 -0500
>>=20
>>    Linux 3.4.22-BGQ-rc1
>>=20
>>=20
>>=20
>>=20
>> _______________________________________________
>> Linuxppc-dev mailing list
>> Linuxppc-dev@lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/linuxppc-dev
>>=20

^ permalink raw reply

* Re: [RFC] Add IBM Blue Gene/Q Platform
From: Jimi Xenidis @ 2012-12-07 13:38 UTC (permalink / raw)
  To: Michael Neuling
  Cc: Andrew T Tauferner, Kumar Gala, Jay Bryant, Josh Boyer,
	Todd Inglett, linuxppc-dev
In-Reply-To: <22874.1354859652@neuling.org>


On Dec 6, 2012, at 11:54 PM, Michael Neuling <mikey@neuling.org> wrote:

>> commit 279c0615917b959a652e81f4ad0d886e2d426d85
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Wed Dec 5 13:43:22 2012 -0500
>>=20
>>    powerpc/book3e: IBM Blue Gene/Q Quad Processing eXtention (QPX)
>>=20
>>    This enables kernel support for the QPX extention and is intended =
for
>>    processors that support it, usually an IBM Blue Gene processor.
>>    Turning it on does not effect other processors but it does add =
code
>>    and will quadruple the per thread save and restore area for the =
FPU
>>    (hense the name).  If you have enabled VSX it will only double the
>>    space.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>=20
> Can you give a diagram of how the QPX registers are layed out.
>=20
> +#if defined(CONFIG_PPC_QPX)
> +#define TS_FPRWIDTH 4
> +#elif defined(CONFIG_VSX)
>=20
> Are they 256 bits wide?

Yes, this is why we nicknamed it the "Quad Hummer" :)
 - 4-wide double precision FPU SIMD
 - 2-wide complex SIMD
 - 4R/2W register file (32x256 bits per thread)
 - 32B (256 bits) datapath to/from L1 cache

>=20
>=20
> +#define QVLFDXA(QRT,RA,RB)	\
> +	.long (0x7c00048f | ((QRT) << 21) | ((RA) << 16) | ((RB) << 11))
>=20
> Put this in ppc-opcode.h.
>=20
> +#if defined(CONFIG_VSX) || defined(CONFIG_PPC_QPX)
> +	/* they are the same MSR bit */
>=20
> OMG!

Ooops, you are correct, this was in the original patch.
I'll double check the work book, but it should be the architected =
VEC/SPV bit which is really for VMX.
I'll track it down.

>=20
>=20
> +BEGIN_FTR_SECTION							=
\
> +	SAVE_32VSRS(n,c,base);						=
\
> +END_FTR_SECTION_IFSET(CPU_FTR_VSX);					=
\
> +BEGIN_FTR_SECTION							=
\
> +	SAVE_32QRS(n,c,base);						=
\
> +END_FTR_SECTION_IFSET(CPU_FTR_QPX);=09
>=20
> I don't think we want to do this.  We are going to end up with 64
> NOPS here somewhere.

Excellent point, NOPs are cheap on most processors but not A2 and a lot =
of embedded, I can wrap some branches with the FTR instead.
Do you have a concern on the code size?

>=20
> I'd like to see this patch broken into different parts.

I'm not sure how _this_ patch:
  =
<https://github.com/jimix/linux-bgq/commit/279c0615917b959a652e81f4ad0d886=
e2d426d85>
could be broken up, please advise.

>=20
> Also, have you boot tested this change on a VSX enabled box?

I can try, I may bug you for help.
Is there a commonly test (or apps) I should run?

-jx


>=20
> Mikey

^ permalink raw reply

* Re: [RFC] Add IBM Blue Gene/Q Platform
From: Jimi Xenidis @ 2012-12-07 13:12 UTC (permalink / raw)
  To: Michael Neuling
  Cc: Andrew T Tauferner, Kumar Gala, Jay Bryant, Todd Inglett,
	linuxppc-dev
In-Reply-To: <22146.1354858896@neuling.org>


On Dec 6, 2012, at 11:41 PM, Michael Neuling <mikey@neuling.org> wrote:

>> commit f6e3c1f706cb6922349d639a74ff6c50acc8b9f8
>> Author: Jimi Xenidis <jimix@pobox.com>
>> Date:   Wed Dec 5 13:41:25 2012 -0500
>>=20
>>    powerpc: Remove unecessary VSX symbols
>>=20
>>    The symbol THREAD_VSR0 is defined to be the same as THREAD_FPR0.  =
Its
>>    presence causes build issues with more complex configurations.
>>=20
>>    Signed-off-by: Jimi Xenidis <jimix@pobox.com>
>>=20
>=20
> Can you explain what these "complex configurations" are?

In an earlier email we discussed the possibility that there was the =
possibility/desire that a single binary could support either FPU, VSX =
and the new QPX.
However, if a CONFIG_VSX is not defined then THREAD_VSR0 does not get =
defined even though there might be some code that refers to it.
Since it is an alias for the same piece of storage I was hoping to solve =
my config issue and be simplify the code.

-jx


>=20
> Mikey

^ permalink raw reply

* [PATCH] Revert "crypto: caam - Updated SEC-4.0 device tree binding for ERA information."
From: Vakul Garg @ 2012-12-07  8:57 UTC (permalink / raw)
  To: linux-crypto, linuxppc-dev, devicetree-discuss

This reverts commit a2c0911c09190125f52c9941b9d187f601c2f7be.

Signed-off-by: Vakul Garg <vakul@freescale.com>
---
Instead of adding SEC era information in crypto node's compatible, a new
property 'fsl,sec-era' is being introduced into crypto node.

 .../devicetree/bindings/crypto/fsl-sec4.txt        |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt
index fc9ce6f..bd7ce12 100644
--- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt
+++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt
@@ -54,8 +54,7 @@ PROPERTIES
    - compatible
       Usage: required
       Value type: <string>
-      Definition: Must include "fsl,sec-v4.0". Also includes SEC
-           ERA versions (optional) with which the device is compatible.
+      Definition: Must include "fsl,sec-v4.0"
 
    - #address-cells
        Usage: required
@@ -107,7 +106,7 @@ PROPERTIES
 
 EXAMPLE
 	crypto@300000 {
-		compatible = "fsl,sec-v4.0", "fsl,sec-era-v2.0";
+		compatible = "fsl,sec-v4.0";
 		#address-cells = <1>;
 		#size-cells = <1>;
 		reg = <0x300000 0x10000>;
-- 
1.7.7.6

^ permalink raw reply related

* [PATCH 6/6] powerpc: Implement PPR save/restore
From: Haren Myneni @ 2012-12-07  7:51 UTC (permalink / raw)
  To: benh, paulus, anton, michael.neuling, linuxppc-dev

[PATCH 6/6] powerpc: Implement PPR save/restore

When the task enters in to kernel space, the user defined priority (PPR)
will be saved in to PACA at the beginning of first level exception
vector and then copy from PACA to thread_info in second level vector.
PPR will be restored from thread_info before exits the kernel space.

P7/P8 temporarily raises the thread priority to higher level during
exception until the program executes HMT_* calls. But it will not modify
PPR register. So we save PPR value whenever some register is available
to use and then calls HMT_MEDIUM to increase the priority. This feature
supports on P7 or later processors.

We save/ restore PPR for all exception vectors except system call entry.
GLIBC will be saving / restore for system calls. So the default PPR
value (3) will be set for the system call exit when the task returned
to the user space.

Signed-off-by: Haren Myneni <haren@us.ibm.com>
---
 arch/powerpc/include/asm/exception-64s.h |   18 ++++++++++--------
 arch/powerpc/kernel/entry_64.S           |    3 +++
 arch/powerpc/kernel/exceptions-64s.S     |   23 +++++++++++++----------
 3 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 090fcd1..c235867 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -147,8 +147,9 @@ END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,943)
 
 #define __EXCEPTION_PROLOG_1(area, extra, vec)				\
 	GET_PACA(r13);							\
-	std	r9,area+EX_R9(r13);	/* save r9 - r12 */		\
-	std	r10,area+EX_R10(r13);					\
+	std	r9,area+EX_R9(r13);	/* save r9 */			\
+	HMT_MEDIUM_PPR_SAVE(area, r9);					\
+	std	r10,area+EX_R10(r13);	/* save r10 - r12 */		\
 	BEGIN_FTR_SECTION_NESTED(66);					\
 	mfspr	r10,SPRN_CFAR;						\
 	std	r10,area+EX_CFAR(r13);					\
@@ -264,6 +265,7 @@ do_kvm_##n:								\
 	std	r10,GPR1(r1);		/* save r1 in stackframe	*/ \
 	beq	4f;			/* if from kernel mode		*/ \
 	ACCOUNT_CPU_USER_ENTRY(r9, r10);				   \
+	SAVE_PPR(area, r9, r10);					   \
 4:	std	r2,GPR2(r1);		/* save r2 in stackframe	*/ \
 	SAVE_4GPRS(3, r1);		/* save r3 - r6 in stackframe	*/ \
 	SAVE_2GPRS(7, r1);		/* save r7, r8 in stackframe	*/ \
@@ -305,7 +307,7 @@ do_kvm_##n:								\
 	. = loc;					\
 	.globl label##_pSeries;				\
 label##_pSeries:					\
-	HMT_MEDIUM;					\
+	HMT_MEDIUM_PPR_DISCARD;				\
 	SET_SCRATCH0(r13);		/* save r13 */		\
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common,	\
 				 EXC_STD, KVMTEST_PR, vec)
@@ -314,7 +316,7 @@ label##_pSeries:					\
 	. = loc;					\
 	.globl label##_hv;				\
 label##_hv:						\
-	HMT_MEDIUM;					\
+	HMT_MEDIUM_PPR_DISCARD;				\
 	SET_SCRATCH0(r13);	/* save r13 */			\
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common,	\
 				 EXC_HV, KVMTEST, vec)
@@ -323,7 +325,7 @@ label##_hv:						\
 	. = loc;					\
 	.globl label##_relon_pSeries;			\
 label##_relon_pSeries:					\
-	HMT_MEDIUM;					\
+	HMT_MEDIUM_PPR_DISCARD;				\
 	/* No guest interrupts come through here */	\
 	SET_SCRATCH0(r13);		/* save r13 */	\
 	EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
@@ -333,7 +335,7 @@ label##_relon_pSeries:					\
 	. = loc;					\
 	.globl label##_relon_hv;			\
 label##_relon_hv:					\
-	HMT_MEDIUM;					\
+	HMT_MEDIUM_PPR_DISCARD;				\
 	/* No guest interrupts come through here */	\
 	SET_SCRATCH0(r13);	/* save r13 */		\
 	EXCEPTION_RELON_PROLOG_PSERIES(PACA_EXGEN, label##_common, \
@@ -368,7 +370,7 @@ label##_relon_hv:					\
 #define SOFTEN_NOTEST_HV(vec)		_SOFTEN_TEST(EXC_HV, vec)
 
 #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra)		\
-	HMT_MEDIUM;							\
+	HMT_MEDIUM_PPR_DISCARD;						\
 	SET_SCRATCH0(r13);    /* save r13 */				\
 	__EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec);		\
 	EXCEPTION_PROLOG_PSERIES_1(label##_common, h);
@@ -390,7 +392,7 @@ label##_hv:								\
 				    EXC_HV, SOFTEN_TEST_HV)
 
 #define __MASKABLE_RELON_EXCEPTION_PSERIES(vec, label, h, extra)	\
-	HMT_MEDIUM;							\
+	HMT_MEDIUM_PPR_DISCARD;						\
 	SET_SCRATCH0(r13);    /* save r13 */				\
 	__EXCEPTION_PROLOG_1(PACA_EXGEN, extra, vec);		\
 	EXCEPTION_RELON_PROLOG_PSERIES_1(label##_common, h);
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 4e78247..886fc64 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -227,6 +227,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
 
 	beq-	1f
 	ACCOUNT_CPU_USER_EXIT(r11, r12)
+	HMT_MEDIUM_LOW_HAS_PPR
 	ld	r13,GPR13(r1)	/* only restore r13 if returning to usermode */
 1:	ld	r2,GPR2(r1)
 	ld	r1,GPR1(r1)
@@ -303,6 +304,7 @@ syscall_exit_work:
 	subi	r12,r12,TI_FLAGS
 
 4:	/* Anything else left to do? */
+	SET_DEFAULT_THREAD_PPR(r3, r9)		/* Set thread.ppr = 3 */
 	andi.	r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
 	beq	.ret_from_except_lite
 
@@ -764,6 +766,7 @@ fast_exception_return:
 	andi.	r0,r3,MSR_PR
 	beq	1f
 	ACCOUNT_CPU_USER_EXIT(r2, r4)
+	RESTORE_PPR(r2, r4)
 	REST_GPR(13, r1)
 1:
 	mtspr	SPRN_SRR1,r3
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 4665e82..6f9d83d 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -104,7 +104,7 @@ __start_interrupts:
 
 	.globl system_reset_pSeries;
 system_reset_pSeries:
-	HMT_MEDIUM;
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 #ifdef CONFIG_PPC_P7_NAP
 BEGIN_FTR_SECTION
@@ -158,7 +158,7 @@ machine_check_pSeries_1:
 	. = 0x300
 	.globl data_access_pSeries
 data_access_pSeries:
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 BEGIN_FTR_SECTION
 	b	data_access_check_stab
@@ -170,7 +170,7 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
 	. = 0x380
 	.globl data_access_slb_pSeries
 data_access_slb_pSeries:
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 	EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST, 0x380)
 	std	r3,PACA_EXSLB+EX_R3(r13)
@@ -201,7 +201,7 @@ data_access_slb_pSeries:
 	. = 0x480
 	.globl instruction_access_slb_pSeries
 instruction_access_slb_pSeries:
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 	EXCEPTION_PROLOG_1(PACA_EXSLB, KVMTEST_PR, 0x480)
 	std	r3,PACA_EXSLB+EX_R3(r13)
@@ -322,10 +322,11 @@ vsx_unavailable_pSeries_1:
 	. = 0x1500
 	.global denorm_exception_hv
 denorm_exception_hv:
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	mtspr	SPRN_SPRG_HSCRATCH0,r13
 	mfspr	r13,SPRN_SPRG_HPACA
 	std	r9,PACA_EXGEN+EX_R9(r13)
+	HMT_MEDIUM_PPR_SAVE(PACA_EXGEN, r9)
 	std	r10,PACA_EXGEN+EX_R10(r13)
 	std	r11,PACA_EXGEN+EX_R11(r13)
 	std	r12,PACA_EXGEN+EX_R12(r13)
@@ -367,7 +368,7 @@ denorm_exception_hv:
 machine_check_pSeries:
 	.globl machine_check_fwnmi
 machine_check_fwnmi:
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)		/* save r13 */
 	EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common,
 				 EXC_STD, KVMTEST, 0x200)
@@ -496,6 +497,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
 	mtspr	SPRN_HSRR0,r11
 	mtcrf	0x80,r9
 	ld	r9,PACA_EXGEN+EX_R9(r13)
+	RESTORE_PPR_PACA(PACA_EXGEN, r10)
 	ld	r10,PACA_EXGEN+EX_R10(r13)
 	ld	r11,PACA_EXGEN+EX_R11(r13)
 	ld	r12,PACA_EXGEN+EX_R12(r13)
@@ -586,7 +588,7 @@ _GLOBAL(__replay_interrupt)
 	.globl system_reset_fwnmi
       .align 7
 system_reset_fwnmi:
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)		/* save r13 */
 	EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
 				 NOTEST, 0x100)
@@ -690,7 +692,7 @@ machine_check_common:
 	. = 0x4380
 	.globl data_access_slb_relon_pSeries
 data_access_slb_relon_pSeries:
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 	EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x380)
 	std	r3,PACA_EXSLB+EX_R3(r13)
@@ -715,7 +717,7 @@ data_access_slb_relon_pSeries:
 	. = 0x4480
 	.globl instruction_access_slb_relon_pSeries
 instruction_access_slb_relon_pSeries:
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 	EXCEPTION_PROLOG_1(PACA_EXSLB, NOTEST, 0x480)
 	std	r3,PACA_EXSLB+EX_R3(r13)
@@ -1036,6 +1038,7 @@ _GLOBAL(slb_miss_realmode)
 	mtcrf	0x01,r9		/* slb_allocate uses cr0 and cr7 */
 .machine	pop
 
+	RESTORE_PPR_PACA(PACA_EXSLB, r9)
 	ld	r9,PACA_EXSLB+EX_R9(r13)
 	ld	r10,PACA_EXSLB+EX_R10(r13)
 	ld	r11,PACA_EXSLB+EX_R11(r13)
@@ -1383,7 +1386,7 @@ initial_stab:
 
 #ifdef CONFIG_PPC_POWERNV
 _GLOBAL(opal_mc_secondary_handler)
-	HMT_MEDIUM
+	HMT_MEDIUM_PPR_DISCARD
 	SET_SCRATCH0(r13)
 	GET_PACA(r13)
 	clrldi	r3,r3,2
-- 
1.7.1

^ permalink raw reply related

* [PATCH 5/6] powerpc: Macros for saving/restore PPR
From: Haren Myneni @ 2012-12-07  7:50 UTC (permalink / raw)
  To: benh, paulus, anton, michael.neuling, linuxppc-dev

[PATCH 5/6] powerpc: Macros for saving/restore PPR

Several macros are defined for saving and restore user defined PPR value.

Signed-off-by: Haren Myneni <haren@us.ibm.com>
---
 arch/powerpc/include/asm/exception-64s.h |   37 ++++++++++++++++++++++++++++++
 arch/powerpc/include/asm/ppc_asm.h       |   25 ++++++++++++++++++++
 arch/powerpc/include/asm/reg.h           |    1 +
 3 files changed, 63 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 3b24ca9..090fcd1 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -108,6 +108,43 @@
 #define RESTORE_LR(reg, area)
 #endif
 
+/*
+ * PPR save/restore macros used in exceptions_64s.S  
+ * Used for P7 or later processors
+ */
+#define SAVE_PPR(area, ra, rb)						\
+BEGIN_FTR_SECTION_NESTED(940)						\
+	ld	ra,PACACURRENT(r13);					\
+	ld	rb,area+EX_PPR(r13);	/* Read PPR from paca */	\
+	std	rb,TASKTHREADPPR(ra);					\
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,940)
+
+#define RESTORE_PPR_PACA(area, ra)					\
+BEGIN_FTR_SECTION_NESTED(941)						\
+	ld	ra,area+EX_PPR(r13);					\
+	mtspr	SPRN_PPR,ra;						\
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,941)
+
+/*
+ * Increase the priority on systems where PPR save/restore is not
+ * implemented/ supported.
+ */
+#define HMT_MEDIUM_PPR_DISCARD						\
+BEGIN_FTR_SECTION_NESTED(942)						\
+	HMT_MEDIUM;							\
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,0,942)  /*non P7*/		
+
+/*
+ * Save PPR in paca whenever some register is available to use.
+ * Then increase the priority.
+ */
+#define HMT_MEDIUM_PPR_SAVE(area, ra)					\
+BEGIN_FTR_SECTION_NESTED(943)						\
+	mfspr	ra,SPRN_PPR;						\
+	std	ra,area+EX_PPR(r13);					\
+	HMT_MEDIUM;							\
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,943) 
+
 #define __EXCEPTION_PROLOG_1(area, extra, vec)				\
 	GET_PACA(r13);							\
 	std	r9,area+EX_R9(r13);	/* save r9 - r12 */		\
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 376e36d..c2d0e58 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -389,6 +389,31 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
 	FTR_SECTION_ELSE_NESTED(848);	\
 	mtocrf (FXM), RS;		\
 	ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_NOEXECUTE, 848)
+
+/*
+ * PPR restore macros used in entry_64.S
+ * Used for P7 or later processors
+ */
+#define HMT_MEDIUM_LOW_HAS_PPR						\
+BEGIN_FTR_SECTION_NESTED(944)						\
+	HMT_MEDIUM_LOW;							\
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,944)
+
+#define SET_DEFAULT_THREAD_PPR(ra, rb)					\
+BEGIN_FTR_SECTION_NESTED(945)						\
+	lis	ra,INIT_PPR@highest;	/* default ppr=3 */		\
+	ld	rb,PACACURRENT(r13);					\
+	sldi	ra,ra,32;	/* 11- 13 bits are used for ppr */	\
+	std	ra,TASKTHREADPPR(rb);					\
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,945)
+
+#define RESTORE_PPR(ra, rb)						\
+BEGIN_FTR_SECTION_NESTED(946)						\
+	ld	ra,PACACURRENT(r13);					\
+	ld	rb,TASKTHREADPPR(ra);					\
+	mtspr	SPRN_PPR,rb;	/* Restore PPR */			\
+END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,946)
+
 #endif
 
 /*
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 1b853f7..d395426 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -289,6 +289,7 @@
 #define SPRN_DBAT6U	0x23C	/* Data BAT 6 Upper Register */
 #define SPRN_DBAT7L	0x23F	/* Data BAT 7 Lower Register */
 #define SPRN_DBAT7U	0x23E	/* Data BAT 7 Upper Register */
+#define SPRN_PPR	0x380	/* SMT Thread status Register */
 
 #define SPRN_DEC	0x016		/* Decrement Register */
 #define SPRN_DER	0x095		/* Debug Enable Regsiter */
-- 
1.7.1

^ permalink raw reply related

* [PATCH 4/6] powerpc: Define ppr in thread_struct
From: Haren Myneni @ 2012-12-07  7:49 UTC (permalink / raw)
  To: benh, paulus, anton, michael.neuling, linuxppc-dev

[PATCH 4/6] powerpc: Define ppr in thread_struct

ppr in thread_struct is used to save PPR and restore it before process exits
from kernel.

This patch sets the default priority to 3 when tasks are created such
that users can use 4 for higher priority tasks.

Signed-off-by: Haren Myneni <haren@us.ibm.com>
---
 arch/powerpc/include/asm/processor.h |   12 ++++++++++++
 arch/powerpc/kernel/asm-offsets.c    |    1 +
 arch/powerpc/kernel/process.c        |    2 ++
 3 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 8750204..37f87f0 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -18,6 +18,16 @@
 #define TS_FPRWIDTH 1
 #endif
 
+#ifdef CONFIG_PPC64
+/* Default SMT priority is set to 3. Use 11- 13bits to save priority. */
+#define PPR_PRIORITY 3
+#ifdef __ASSEMBLY__
+#define INIT_PPR (PPR_PRIORITY << 50)
+#else
+#define INIT_PPR ((u64)PPR_PRIORITY << 50)
+#endif /* __ASSEMBLY__ */
+#endif /* CONFIG_PPC64 */
+
 #ifndef __ASSEMBLY__
 #include <linux/compiler.h>
 #include <linux/cache.h>
@@ -245,6 +255,7 @@ struct thread_struct {
 #ifdef CONFIG_PPC64
 	unsigned long	dscr;
 	int		dscr_inherit;
+	unsigned long	ppr;	/* used to save/restore SMT priority */
 #endif
 };
 
@@ -278,6 +289,7 @@ struct thread_struct {
 	.fpr = {{0}}, \
 	.fpscr = { .val = 0, }, \
 	.fpexc_mode = 0, \
+	.ppr = INIT_PPR, \
 }
 #endif
 
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 7523539..41f65ec 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -77,6 +77,7 @@ int main(void)
 	DEFINE(NMI_MASK, NMI_MASK);
 	DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr));
 	DEFINE(THREAD_DSCR_INHERIT, offsetof(struct thread_struct, dscr_inherit));
+	DEFINE(TASKTHREADPPR, offsetof(struct task_struct, thread.ppr));
 #else
 	DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
 #endif /* CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index ba48233..2563acc 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -814,6 +814,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
 		p->thread.dscr_inherit = current->thread.dscr_inherit;
 		p->thread.dscr = current->thread.dscr;
 	}
+	if (cpu_has_feature(CPU_FTR_HAS_PPR))
+		p->thread.ppr = INIT_PPR;
 #endif
 	/*
 	 * The PPC64 ABI makes use of a TOC to contain function 
-- 
1.7.1

^ permalink raw reply related

* [PATCH 3/6] powerpc: Increase exceptions arrays in paca struct to save PPR
From: Haren Myneni @ 2012-12-07  7:48 UTC (permalink / raw)
  To: benh, paulus, anton, michael.neuling, linuxppc-dev

[PATCH 3/6] powerpc: Increase exceptions arrays in paca struct to save PPR

Using paca to save user defined PPR value in the first level exception vector.

Signed-off-by: Haren Myneni <haren@us.ibm.com>
---
 arch/powerpc/include/asm/exception-64s.h |    1 +
 arch/powerpc/include/asm/paca.h          |    6 +++---
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 697de09..3b24ca9 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -47,6 +47,7 @@
 #define EX_R3		64
 #define EX_LR		72
 #define EX_CFAR		80
+#define EX_PPR		88	/* SMT thread status register (priority) */
 
 #ifdef CONFIG_RELOCATABLE
 #define EXCEPTION_RELON_PROLOG_PSERIES_1(label, h)			\
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index e9e7a69..c47d687 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -93,9 +93,9 @@ struct paca_struct {
 	 * Now, starting in cacheline 2, the exception save areas
 	 */
 	/* used for most interrupts/exceptions */
-	u64 exgen[11] __attribute__((aligned(0x80)));
-	u64 exmc[11];		/* used for machine checks */
-	u64 exslb[11];		/* used for SLB/segment table misses
+	u64 exgen[12] __attribute__((aligned(0x80)));
+	u64 exmc[12];		/* used for machine checks */
+	u64 exslb[12];		/* used for SLB/segment table misses
  				 * on the linear mapping */
 	/* SLB related definitions */
 	u16 vmalloc_sllp;
-- 
1.7.1

^ permalink raw reply related

* [PATCH 2/6] powerpc: Enable PPR save/restore
From: Haren Myneni @ 2012-12-07  7:47 UTC (permalink / raw)
  To: benh, paulus, anton, michael.neuling, linuxppc-dev

[PATCH 2/6] powerpc: Enable PPR save/restore

SMT thread status register (PPR) is used to set thread priority. This patch
enables PPR save/restore feature (CPU_FTR_HAS_PPR) on POWER7 and POWER8 systems.

Signed-off-by: Haren Myneni <haren@us.ibm.com>
---
 arch/powerpc/include/asm/cputable.h |    7 +++++--
 1 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 76f81bd..241d65d 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -171,6 +171,7 @@ extern const char *powerpc_base_platform;
 #define CPU_FTR_POPCNTD			LONG_ASM_CONST(0x0800000000000000)
 #define CPU_FTR_ICSWX			LONG_ASM_CONST(0x1000000000000000)
 #define CPU_FTR_VMX_COPY		LONG_ASM_CONST(0x2000000000000000)
+#define	CPU_FTR_HAS_PPR			LONG_ASM_CONST(0x4000000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -400,7 +401,8 @@ extern const char *powerpc_base_platform;
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
 	    CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
 	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
-	    CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY)
+	    CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | \
+	    CPU_FTR_VMX_COPY | CPU_FTR_HAS_PPR)
 #define CPU_FTRS_POWER8 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_ARCH_206 |\
 	    CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -408,7 +410,8 @@ extern const char *powerpc_base_platform;
 	    CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
 	    CPU_FTR_DSCR | CPU_FTR_SAO  | \
 	    CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
-	    CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY)
+	    CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | \
+	    CPU_FTR_VMX_COPY | CPU_FTR_HAS_PPR)
 #define CPU_FTRS_CELL	(CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
 	    CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
 	    CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
-- 
1.7.1

^ permalink raw reply related

* [PATCH 1/6] powerpc: Move branch instruction from ACCOUNT_CPU_USER_ENTRY to caller
From: Haren Myneni @ 2012-12-07  7:46 UTC (permalink / raw)
  To: benh, paulus, anton, michael.neuling, linuxppc-dev

[PATCH 1/6] powerpc: Move branch instruction from ACCOUNT_CPU_USER_ENTRY to caller

The first instruction in ACCOUNT_CPU_USER_ENTRY is 'beq' which checks for
exceptions coming from kernel mode. PPR value will be saved immediately after
ACCOUNT_CPU_USER_ENTRY and is also for user level exceptions. So moved this
branch instruction in the caller code.

Signed-off-by: Haren Myneni <haren@us.ibm.com>
---
 arch/powerpc/include/asm/exception-64s.h |    3 ++-
 arch/powerpc/include/asm/ppc_asm.h       |    2 --
 arch/powerpc/kernel/entry_64.S           |    3 ++-
 arch/powerpc/kernel/exceptions-64e.S     |    3 ++-
 4 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index ad708dd..697de09 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -224,8 +224,9 @@ do_kvm_##n:								\
 	std	r10,0(r1);		/* make stack chain pointer	*/ \
 	std	r0,GPR0(r1);		/* save r0 in stackframe	*/ \
 	std	r10,GPR1(r1);		/* save r1 in stackframe	*/ \
+	beq	4f;			/* if from kernel mode		*/ \
 	ACCOUNT_CPU_USER_ENTRY(r9, r10);				   \
-	std	r2,GPR2(r1);		/* save r2 in stackframe	*/ \
+4:	std	r2,GPR2(r1);		/* save r2 in stackframe	*/ \
 	SAVE_4GPRS(3, r1);		/* save r3 - r6 in stackframe	*/ \
 	SAVE_2GPRS(7, r1);		/* save r7, r8 in stackframe	*/ \
 	ld	r9,area+EX_R9(r13);	/* move r9, r10 to stackframe	*/ \
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index ea2a86e..376e36d 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -30,7 +30,6 @@
 #define ACCOUNT_STOLEN_TIME
 #else
 #define ACCOUNT_CPU_USER_ENTRY(ra, rb)					\
-	beq	2f;			/* if from kernel mode */	\
 	MFTB(ra);			/* get timebase */		\
 	ld	rb,PACA_STARTTIME_USER(r13);				\
 	std	ra,PACA_STARTTIME(r13);					\
@@ -38,7 +37,6 @@
 	ld	ra,PACA_USER_TIME(r13);					\
 	add	ra,ra,rb;		/* add on to user time */	\
 	std	ra,PACA_USER_TIME(r13);					\
-2:
 
 #define ACCOUNT_CPU_USER_EXIT(ra, rb)					\
 	MFTB(ra);			/* get timebase */		\
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index ad76666..4e78247 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -62,8 +62,9 @@ system_call_common:
 	std	r12,_MSR(r1)
 	std	r0,GPR0(r1)
 	std	r10,GPR1(r1)
+	beq	2f			/* if from kernel mode */
 	ACCOUNT_CPU_USER_ENTRY(r10, r11)
-	std	r2,GPR2(r1)
+2:	std	r2,GPR2(r1)
 	std	r3,GPR3(r1)
 	mfcr	r2
 	std	r4,GPR4(r1)
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 4684e33..ae54553 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -159,8 +159,9 @@ exc_##n##_common:							    \
 	std	r9,GPR9(r1);		/* save r9 in stackframe */	    \
 	std	r10,_NIP(r1);		/* save SRR0 to stackframe */	    \
 	std	r11,_MSR(r1);		/* save SRR1 to stackframe */	    \
+	beq	2f;			/* if from kernel mode */	    \
 	ACCOUNT_CPU_USER_ENTRY(r10,r11);/* accounting (uses cr0+eq) */	    \
-	ld	r3,excf+EX_R10(r13);	/* get back r10 */		    \
+2:	ld	r3,excf+EX_R10(r13);	/* get back r10 */		    \
 	ld	r4,excf+EX_R11(r13);	/* get back r11 */		    \
 	mfspr	r5,SPRN_SPRG_GEN_SCRATCH;/* get back r13 */		    \
 	std	r12,GPR12(r1);		/* save r12 in stackframe */	    \
-- 
1.7.1

^ permalink raw reply related

* [PATCH 0/6] powerpc: SMT priority (PPR) save and restore
From: Haren Myneni @ 2012-12-07  7:44 UTC (permalink / raw)
  To: benh, paulus, anton, michael.neuling, linuxppc-dev

Ben, 

This patch-set is created against your tree (next branch) and fixed the build failure that you pointed. 

Changes from the previous version:
- Changes for PPR save/restore in denorm_exception_hv, data_access_slb_relon_pSeries and instruction_access_slb_relon_pSeries 
  exception vectors (P8) code.
- Fix build failure with ppc64e_defconfig
- Macro name changes (HMT_MEDIUM_PPR_DISCARD and HMT_MEDIUM_PPR_SAVE) and other fixes as Michael Neuling suggested

[PATCH 0/6] powerpc: SMT priority (PPR) save and restore

On P7/P8 systems, users can define SMT priority levels 2,3 and 4 for
processes so that some can run higher priority than the other ones.
In the current kernel, the default priority is set to 4 which prohibits
processes for using higher priority. Also the kernel boosts the priority to
4 during exceptions without saving the user defined priorities when
the task enters the kernel. So we will be loosing the process PPR value
and can not be restored it back when the task exits the kernel.

This patch-set implements saving and restore the user defined PPR value
for all tasks.

With null_syscall testcase (http://ozlabs.org/~anton/junkcode/null_syscall.c),
this feature takes around extra 10 CPU cycles on average for 25 samples.
 
Haren Myneni (6):
  powerpc: Move branch instruction from ACCOUNT_CPU_USER_ENTRY to caller
  powerpc: Enable PPR save/restore
  powerpc: Increase exceptions arrays in paca struct to save PPR
  powerpc: Define ppr in thread_struct
  powerpc: Macros for saving/restore PPR
  powerpc: Implement PPR save/restore

 arch/powerpc/include/asm/cputable.h      |    7 +++-
 arch/powerpc/include/asm/exception-64s.h |   59 +++++++++++++++++++++++++-----
 arch/powerpc/include/asm/paca.h          |    6 ++--
 arch/powerpc/include/asm/ppc_asm.h       |   27 +++++++++++++-
 arch/powerpc/include/asm/processor.h     |   12 ++++++
 arch/powerpc/include/asm/reg.h           |    1 +
 arch/powerpc/kernel/asm-offsets.c        |    1 +
 arch/powerpc/kernel/entry_64.S           |    6 +++-
 arch/powerpc/kernel/exceptions-64e.S     |    3 +-
 arch/powerpc/kernel/exceptions-64s.S     |   23 +++++++-----
 arch/powerpc/kernel/process.c            |    2 +
 11 files changed, 119 insertions(+), 28 deletions(-)

^ permalink raw reply

* [PATCH] vfio powerpc: enabled on powernv platform
From: Alexey Kardashevskiy @ 2012-12-07  7:35 UTC (permalink / raw)
  To: Alex Williamson
  Cc: kvm, Alexey Kardashevskiy, linux-kernel, Paul Mackerras,
	linuxppc-dev, David Gibson
In-Reply-To: <1354636299.1809.431.camel@bling.home>

This patch initializes IOMMU groups based on the IOMMU
configuration discovered during the PCI scan on POWERNV
(POWER non virtualized) platform. The IOMMU groups are
to be used later by VFIO driver (PCI pass through).

It also implements an API for mapping/unmapping pages for
guest PCI drivers and providing DMA window properties.
This API is going to be used later by QEMU-VFIO to handle
h_put_tce hypercalls from the KVM guest.

Although this driver has been tested only on the POWERNV
platform, it should work on any platform which supports
TCE tables.

To enable VFIO on POWER, enable SPAPR_TCE_IOMMU config
option and configure VFIO as required.

Cc: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
 arch/powerpc/include/asm/iommu.h     |   10 ++
 arch/powerpc/kernel/iommu.c          |  214 ++++++++++++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/pci.c |  134 +++++++++++++++++++++
 drivers/iommu/Kconfig                |    8 ++
 4 files changed, 366 insertions(+)

diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index cbfe678..be3b11b 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -76,6 +76,9 @@ struct iommu_table {
 	struct iommu_pool large_pool;
 	struct iommu_pool pools[IOMMU_NR_POOLS];
 	unsigned long *it_map;       /* A simple allocation bitmap for now */
+#ifdef CONFIG_IOMMU_API
+	struct iommu_group *it_group;
+#endif
 };
 
 struct scatterlist;
@@ -147,5 +150,12 @@ static inline void iommu_restore(void)
 }
 #endif
 
+extern void iommu_reset_table(struct iommu_table *tbl, bool release);
+extern long iommu_clear_tces(struct iommu_table *tbl, unsigned long entry,
+		unsigned long pages);
+extern long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
+		uint64_t tce, enum dma_data_direction direction,
+		unsigned long pages);
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_IOMMU_H */
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index ff5a6ce..123431a 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -44,6 +44,7 @@
 #include <asm/kdump.h>
 #include <asm/fadump.h>
 #include <asm/vio.h>
+#include <asm/tce.h>
 
 #define DBG(...)
 
@@ -856,3 +857,216 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
 		free_pages((unsigned long)vaddr, get_order(size));
 	}
 }
+
+#ifdef CONFIG_IOMMU_API
+/*
+ * SPAPR TCE API
+ */
+
+/*
+ * iommu_reset_table is called when it started/stopped being used
+ */
+void iommu_reset_table(struct iommu_table *tbl, bool release)
+{
+	/*
+	 * Page at 0 is marked as used in iommu_init_table,
+	 * so here we clear it when called with release=false...
+	 */
+	if (!release && (tbl->it_offset == 0))
+		clear_bit(0, tbl->it_map);
+
+	iommu_clear_tces(tbl, tbl->it_offset, tbl->it_size);
+
+	memset(tbl->it_map, 0, (tbl->it_size + 7) >> 3);
+
+	/*
+	 * ... or restore when release=true
+	 */
+	if (release && (tbl->it_offset == 0))
+		set_bit(0, tbl->it_map);
+}
+EXPORT_SYMBOL_GPL(iommu_reset_table);
+
+/*
+ * Returns the number of used IOMMU pages (4K) within
+ * the same system page (4K or 64K).
+ * bitmap_weight is not used as it does not support bigendian maps.
+ * "offset" is an IOMMU page number relative to DMA window start.
+ */
+static int syspage_weight(unsigned long *map, unsigned long offset)
+{
+	int ret = 0, nbits = PAGE_SIZE/IOMMU_PAGE_SIZE;
+
+	/* Aligns TCE entry number to system page boundary */
+	offset &= PAGE_MASK >> IOMMU_PAGE_SHIFT;
+
+	/* Count used 4K pages */
+	while (nbits) {
+		if (test_bit(offset, map))
+			++ret;
+		--nbits;
+		++offset;
+	}
+
+	return ret;
+}
+
+static void tce_flush(struct iommu_table *tbl)
+{
+	/* Flush/invalidate TLB caches if necessary */
+	if (ppc_md.tce_flush)
+		ppc_md.tce_flush(tbl);
+
+	/* Make sure updates are seen by hardware */
+	mb();
+}
+
+/*
+ * iommu_clear_tces clears tces and returned the number of system pages
+ * which it called put_page() on
+ */
+static long clear_tces_nolock(struct iommu_table *tbl, unsigned long entry,
+		unsigned long pages)
+{
+	int i, retpages = 0, clr;
+	unsigned long oldtce, oldweight;
+	struct page *page;
+
+	for (i = 0; i < pages; ++i) {
+		if (!test_bit(entry + i - tbl->it_offset, tbl->it_map))
+			continue;
+
+		oldtce = ppc_md.tce_get(tbl, entry + i);
+		ppc_md.tce_free(tbl, entry + i, 1);
+
+		oldweight = syspage_weight(tbl->it_map,
+				entry + i - tbl->it_offset);
+		clr = __test_and_clear_bit(entry + i - tbl->it_offset,
+				tbl->it_map);
+
+		if (WARN_ON(!(oldtce & (TCE_PCI_WRITE | TCE_PCI_READ))))
+			continue;
+
+		page = pfn_to_page(oldtce >> PAGE_SHIFT);
+
+		if (WARN_ON(!page))
+			continue;
+
+		if (oldtce & TCE_PCI_WRITE)
+			SetPageDirty(page);
+
+		put_page(page);
+
+		/* That was the last IOMMU page within the system page */
+		if ((oldweight == 1) && clr)
+			++retpages;
+	}
+
+	return retpages;
+}
+
+/*
+ * iommu_clear_tces clears tces and returned the number
+ * of released system pages
+ */
+long iommu_clear_tces(struct iommu_table *tbl, unsigned long entry,
+		unsigned long pages)
+{
+	int ret;
+	struct iommu_pool *pool = get_pool(tbl, entry);
+
+	spin_lock(&(pool->lock));
+	ret = clear_tces_nolock(tbl, entry, pages);
+	tce_flush(tbl);
+	spin_unlock(&(pool->lock));
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_clear_tces);
+
+static int put_tce(struct iommu_table *tbl, unsigned long entry,
+		uint64_t tce, enum dma_data_direction direction)
+{
+	int ret;
+	struct page *page = NULL;
+	unsigned long kva, offset, oldweight;
+
+	/* Map new TCE */
+	offset = (tce & IOMMU_PAGE_MASK) - (tce & PAGE_MASK);
+	ret = get_user_pages_fast(tce & PAGE_MASK, 1,
+			direction != DMA_TO_DEVICE, &page);
+	if (ret != 1) {
+		pr_err("tce_vfio: get_user_pages_fast failed tce=%llx ioba=%lx ret=%d\n",
+				tce, entry << IOMMU_PAGE_SHIFT, ret);
+		return -EFAULT;
+	}
+
+	kva = (unsigned long) page_address(page);
+	kva += offset;
+
+	/* tce_build receives a virtual address */
+	ret = ppc_md.tce_build(tbl, entry, 1, kva, direction, NULL);
+
+	/* tce_build() only returns non-zero for transient errors */
+	if (unlikely(ret)) {
+		pr_err("tce_vfio: tce_put failed on tce=%llx ioba=%lx kva=%lx ret=%d\n",
+				tce, entry << IOMMU_PAGE_SHIFT, kva, ret);
+		put_page(page);
+		return -EIO;
+	}
+
+	/* Calculate if new system page has been locked */
+	oldweight = syspage_weight(tbl->it_map, entry - tbl->it_offset);
+	__set_bit(entry - tbl->it_offset, tbl->it_map);
+
+	return (oldweight == 0) ? 1 : 0;
+}
+
+/*
+ * iommu_put_tces builds tces and returned the number of actually
+ * locked system pages
+ */
+long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
+		uint64_t tce, enum dma_data_direction direction,
+		unsigned long pages)
+{
+	int i, ret = 0, retpages = 0;
+	struct iommu_pool *pool = get_pool(tbl, entry);
+
+	BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
+	BUG_ON(direction == DMA_NONE);
+
+	spin_lock(&(pool->lock));
+
+	/* Check if any is in use */
+	for (i = 0; i < pages; ++i) {
+		if (test_bit(entry + i - tbl->it_offset, tbl->it_map)) {
+			spin_unlock(&(pool->lock));
+			return -EBUSY;
+		}
+	}
+
+	/* Put tces to the table */
+	for (i = 0; (i < pages) && (ret >= 0); ++i, tce += IOMMU_PAGE_SIZE) {
+		ret = put_tce(tbl, entry + i, tce, direction);
+		if (ret == 1)
+			++retpages;
+	}
+
+	/*
+	 * If failed, release locked pages, otherwise return the number
+	 * of locked system pages
+	 */
+	if (ret < 0)
+		clear_tces_nolock(tbl, entry, i);
+	else
+		ret = retpages;
+
+	tce_flush(tbl);
+	spin_unlock(&(pool->lock));
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_put_tces);
+
+#endif /* CONFIG_IOMMU_API */
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 05205cf..1b970bf 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -20,6 +20,7 @@
 #include <linux/irq.h>
 #include <linux/io.h>
 #include <linux/msi.h>
+#include <linux/iommu.h>
 
 #include <asm/sections.h>
 #include <asm/io.h>
@@ -613,3 +614,136 @@ void __init pnv_pci_init(void)
 	ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs;
 #endif
 }
+
+#ifdef CONFIG_IOMMU_API
+/*
+ * IOMMU groups support required by VFIO
+ */
+static int add_device(struct device *dev)
+{
+	struct iommu_table *tbl;
+	int ret = 0;
+
+	if (WARN_ON(dev->iommu_group)) {
+		pr_warn("tce_vfio: device %s is already in iommu group %d, skipping\n",
+				dev_name(dev),
+				iommu_group_id(dev->iommu_group));
+		return -EBUSY;
+	}
+
+	tbl = get_iommu_table_base(dev);
+	if (!tbl) {
+		pr_debug("tce_vfio: skipping device %s with no tbl\n",
+				dev_name(dev));
+		return 0;
+	}
+
+	pr_debug("tce_vfio: adding %s to iommu group %d\n",
+			dev_name(dev), iommu_group_id(tbl->it_group));
+
+	ret = iommu_group_add_device(tbl->it_group, dev);
+	if (ret < 0)
+		pr_err("tce_vfio: %s has not been added, ret=%d\n",
+				dev_name(dev), ret);
+
+	return ret;
+}
+
+static void del_device(struct device *dev)
+{
+	iommu_group_remove_device(dev);
+}
+
+static int iommu_bus_notifier(struct notifier_block *nb,
+			      unsigned long action, void *data)
+{
+	struct device *dev = data;
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		return add_device(dev);
+	case BUS_NOTIFY_DEL_DEVICE:
+		del_device(dev);
+		return 0;
+	default:
+		return 0;
+	}
+}
+
+static struct notifier_block tce_iommu_bus_nb = {
+	.notifier_call = iommu_bus_notifier,
+};
+
+static void group_release(void *iommu_data)
+{
+	struct iommu_table *tbl = iommu_data;
+	tbl->it_group = NULL;
+}
+
+static int __init tce_iommu_init(void)
+{
+	struct pci_dev *pdev = NULL;
+	struct iommu_table *tbl;
+	struct iommu_group *grp;
+
+	/* Allocate and initialize IOMMU groups */
+	for_each_pci_dev(pdev) {
+		tbl = get_iommu_table_base(&pdev->dev);
+		if (!tbl)
+			continue;
+
+		/* Skip already initialized */
+		if (tbl->it_group)
+			continue;
+
+		grp = iommu_group_alloc();
+		if (IS_ERR(grp)) {
+			pr_info("tce_vfio: cannot create new IOMMU group, ret=%ld\n",
+					PTR_ERR(grp));
+			return PTR_ERR(grp);
+		}
+		tbl->it_group = grp;
+		iommu_group_set_iommudata(grp, tbl, group_release);
+	}
+
+	bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+
+	/* Add PCI devices to VFIO groups */
+	for_each_pci_dev(pdev)
+		add_device(&pdev->dev);
+
+	return 0;
+}
+
+static void __exit tce_iommu_cleanup(void)
+{
+	struct pci_dev *pdev = NULL;
+	struct iommu_table *tbl;
+	struct iommu_group *grp = NULL;
+
+	bus_unregister_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+
+	/* Delete PCI devices from VFIO groups */
+	for_each_pci_dev(pdev)
+		del_device(&pdev->dev);
+
+	/* Release VFIO groups */
+	for_each_pci_dev(pdev) {
+		tbl = get_iommu_table_base(&pdev->dev);
+		if (!tbl)
+			continue;
+		grp = tbl->it_group;
+
+		/* Skip (already) uninitialized */
+		if (!grp)
+			continue;
+
+		/* Do actual release, group_release() is expected to work */
+		iommu_group_put(grp);
+		BUG_ON(tbl->it_group);
+	}
+}
+
+module_init(tce_iommu_init);
+module_exit(tce_iommu_cleanup);
+#endif /* CONFIG_IOMMU_API */
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 9f69b56..29d11dc 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -187,4 +187,12 @@ config EXYNOS_IOMMU_DEBUG
 
 	  Say N unless you need kernel log message for IOMMU debugging
 
+config SPAPR_TCE_IOMMU
+	bool "sPAPR TCE IOMMU Support"
+	depends on PPC_POWERNV
+	select IOMMU_API
+	help
+	  Enables bits of IOMMU API required by VFIO. The iommu_ops is
+	  still not implemented.
+
 endif # IOMMU_SUPPORT
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH] vfio powerpc: implemented IOMMU driver for VFIO
From: Alexey Kardashevskiy @ 2012-12-07  7:34 UTC (permalink / raw)
  To: Alex Williamson
  Cc: kvm, Alexey Kardashevskiy, linux-kernel, Paul Mackerras,
	linuxppc-dev, David Gibson
In-Reply-To: <1354557206.1809.377.camel@bling.home>

VFIO implements platform independent stuff such as
a PCI driver, BAR access (via read/write on a file descriptor
or direct mapping when possible) and IRQ signaling.

The platform dependent part includes IOMMU initialization
and handling. This patch implements an IOMMU driver for VFIO
which does mapping/unmapping pages for the guest IO and
provides information about DMA window (required by a POWERPC
guest).

The counterpart in QEMU is required to support this functionality.

Cc: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
 drivers/vfio/Kconfig                |    6 +
 drivers/vfio/Makefile               |    1 +
 drivers/vfio/vfio_iommu_spapr_tce.c |  348 +++++++++++++++++++++++++++++++++++
 include/linux/vfio.h                |   30 +++
 4 files changed, 385 insertions(+)
 create mode 100644 drivers/vfio/vfio_iommu_spapr_tce.c

diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index 7cd5dec..b464687 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -3,10 +3,16 @@ config VFIO_IOMMU_TYPE1
 	depends on VFIO
 	default n
 
+config VFIO_IOMMU_SPAPR_TCE
+	tristate
+	depends on VFIO && SPAPR_TCE_IOMMU
+	default n
+
 menuconfig VFIO
 	tristate "VFIO Non-Privileged userspace driver framework"
 	depends on IOMMU_API
 	select VFIO_IOMMU_TYPE1 if X86
+	select VFIO_IOMMU_SPAPR_TCE if PPC_POWERNV
 	help
 	  VFIO provides a framework for secure userspace device drivers.
 	  See Documentation/vfio.txt for more details.
diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
index 2398d4a..72bfabc 100644
--- a/drivers/vfio/Makefile
+++ b/drivers/vfio/Makefile
@@ -1,3 +1,4 @@
 obj-$(CONFIG_VFIO) += vfio.o
 obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
+obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
 obj-$(CONFIG_VFIO_PCI) += pci/
diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
new file mode 100644
index 0000000..b0f81fe
--- /dev/null
+++ b/drivers/vfio/vfio_iommu_spapr_tce.c
@@ -0,0 +1,348 @@
+/*
+ * VFIO: IOMMU DMA mapping support for TCE on POWER
+ *
+ * Copyright (C) 2012 IBM Corp.  All rights reserved.
+ *     Author: Alexey Kardashevskiy <aik@ozlabs.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Derived from original vfio_iommu_type1.c:
+ * Copyright (C) 2012 Red Hat, Inc.  All rights reserved.
+ *     Author: Alex Williamson <alex.williamson@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/err.h>
+#include <linux/vfio.h>
+#include <asm/iommu.h>
+
+#define DRIVER_VERSION  "0.1"
+#define DRIVER_AUTHOR   "aik@ozlabs.ru"
+#define DRIVER_DESC     "VFIO IOMMU SPAPR TCE"
+
+static void tce_iommu_detach_group(void *iommu_data,
+		struct iommu_group *iommu_group);
+
+/*
+ * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
+ */
+
+/*
+ * This code handles mapping and unmapping of user data buffers
+ * into DMA'ble space using the IOMMU
+ */
+
+#define NPAGE_TO_SIZE(npage)	((size_t)(npage) << PAGE_SHIFT)
+
+struct vwork {
+	struct mm_struct	*mm;
+	long			npage;
+	struct work_struct	work;
+};
+
+/* delayed decrement/increment for locked_vm */
+static void lock_acct_bg(struct work_struct *work)
+{
+	struct vwork *vwork = container_of(work, struct vwork, work);
+	struct mm_struct *mm;
+
+	mm = vwork->mm;
+	down_write(&mm->mmap_sem);
+	mm->locked_vm += vwork->npage;
+	up_write(&mm->mmap_sem);
+	mmput(mm);
+	kfree(vwork);
+}
+
+static void lock_acct(long npage)
+{
+	struct vwork *vwork;
+	struct mm_struct *mm;
+
+	if (!current->mm)
+		return; /* process exited */
+
+	if (down_write_trylock(&current->mm->mmap_sem)) {
+		current->mm->locked_vm += npage;
+		up_write(&current->mm->mmap_sem);
+		return;
+	}
+
+	/*
+	 * Couldn't get mmap_sem lock, so must setup to update
+	 * mm->locked_vm later. If locked_vm were atomic, we
+	 * wouldn't need this silliness
+	 */
+	vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL);
+	if (!vwork)
+		return;
+	mm = get_task_mm(current);
+	if (!mm) {
+		kfree(vwork);
+		return;
+	}
+	INIT_WORK(&vwork->work, lock_acct_bg);
+	vwork->mm = mm;
+	vwork->npage = npage;
+	schedule_work(&vwork->work);
+}
+
+/*
+ * The container descriptor supports only a single group per container.
+ * Required by the API as the container is not supplied with the IOMMU group
+ * at the moment of initialization.
+ */
+struct tce_container {
+	struct mutex lock;
+	struct iommu_table *tbl;
+};
+
+static void *tce_iommu_open(unsigned long arg)
+{
+	struct tce_container *container;
+
+	if (arg != VFIO_SPAPR_TCE_IOMMU) {
+		pr_err("tce_vfio: Wrong IOMMU type\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	container = kzalloc(sizeof(*container), GFP_KERNEL);
+	if (!container)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&container->lock);
+
+	return container;
+}
+
+static void tce_iommu_release(void *iommu_data)
+{
+	struct tce_container *container = iommu_data;
+
+	WARN_ON(container->tbl && !container->tbl->it_group);
+	if (container->tbl && container->tbl->it_group)
+		tce_iommu_detach_group(iommu_data, container->tbl->it_group);
+
+	mutex_destroy(&container->lock);
+
+	kfree(container);
+}
+
+static long tce_iommu_ioctl(void *iommu_data,
+				 unsigned int cmd, unsigned long arg)
+{
+	struct tce_container *container = iommu_data;
+	unsigned long minsz;
+	long ret;
+
+	switch (cmd) {
+	case VFIO_CHECK_EXTENSION:
+		return (arg == VFIO_SPAPR_TCE_IOMMU) ? 1 : 0;
+
+ 	case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
+		struct vfio_iommu_spapr_tce_info info;
+		struct iommu_table *tbl = container->tbl;
+
+		if (WARN_ON(!tbl))
+			return -ENXIO;
+
+		minsz = offsetofend(struct vfio_iommu_spapr_tce_info,
+				dma32_window_size);
+
+		if (copy_from_user(&info, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (info.argsz < minsz)
+			return -EINVAL;
+
+		info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT;
+		info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT;
+		info.flags = 0;
+
+		if (copy_to_user((void __user *)arg, &info, minsz))
+			return -EFAULT;
+
+		return 0;
+	}
+	case VFIO_IOMMU_MAP_DMA: {
+		vfio_iommu_spapr_tce_dma_map param;
+		struct iommu_table *tbl = container->tbl;
+		enum dma_data_direction direction;
+		unsigned long locked, lock_limit;
+
+		if (WARN_ON(!tbl))
+			return -ENXIO;
+
+		minsz = offsetofend(vfio_iommu_spapr_tce_dma_map, size);
+
+		if (copy_from_user(&param, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (param.argsz < minsz)
+			return -EINVAL;
+
+		if ((param.flags & VFIO_DMA_MAP_FLAG_READ) &&
+				(param.flags & VFIO_DMA_MAP_FLAG_WRITE))
+			direction = DMA_BIDIRECTIONAL;
+		else if (param.flags & VFIO_DMA_MAP_FLAG_READ)
+			direction = DMA_TO_DEVICE;
+		else if (param.flags & VFIO_DMA_MAP_FLAG_WRITE)
+			direction = DMA_FROM_DEVICE;
+		else
+			return -EINVAL;
+
+		if ((param.size & ~IOMMU_PAGE_MASK) ||
+				(param.iova & ~IOMMU_PAGE_MASK) ||
+				(param.vaddr & ~IOMMU_PAGE_MASK))
+			return -EINVAL;
+
+		if ((param.iova + param.size) >
+				((tbl->it_offset + tbl->it_size)
+				<< IOMMU_PAGE_SHIFT))
+			return -EINVAL;
+
+		if (param.iova < (tbl->it_offset << IOMMU_PAGE_SHIFT))
+			return -EINVAL;
+
+		/* Account for locked pages */
+		locked = current->mm->locked_vm +
+			(param.size >> PAGE_SHIFT);
+		lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
+		if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
+			pr_warn("RLIMIT_MEMLOCK (%ld) exceeded\n",
+					rlimit(RLIMIT_MEMLOCK));
+			return -ENOMEM;
+		}
+
+		ret = iommu_put_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
+				param.vaddr, direction,
+				param.size >> IOMMU_PAGE_SHIFT);
+
+		if (ret > 0)
+			lock_acct(ret);
+
+		return ret;
+	}
+	case VFIO_IOMMU_UNMAP_DMA: {
+		vfio_iommu_spapr_tce_dma_unmap param;
+		struct iommu_table *tbl = container->tbl;
+
+		if (WARN_ON(!tbl))
+			return -ENXIO;
+
+		minsz = offsetofend(vfio_iommu_spapr_tce_dma_unmap, size);
+
+		if (copy_from_user(&param, (void __user *)arg, minsz))
+			return -EFAULT;
+
+		if (param.argsz < minsz)
+			return -EINVAL;
+
+		if ((param.size & ~IOMMU_PAGE_MASK) ||
+				(param.iova & ~IOMMU_PAGE_MASK))
+			return -EINVAL;
+
+		if ((param.iova + param.size) >
+				((tbl->it_offset + tbl->it_size)
+				<< IOMMU_PAGE_SHIFT))
+			return -EINVAL;
+
+		if (param.iova < (tbl->it_offset << IOMMU_PAGE_SHIFT))
+			return -EINVAL;
+
+		ret = iommu_clear_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
+				param.size >> IOMMU_PAGE_SHIFT);
+
+		if (ret > 0)
+			lock_acct(-ret);
+
+		return ret;
+	}
+	default:
+		pr_warn("tce_vfio: unexpected cmd %x\n", cmd);
+	}
+
+	return -ENOTTY;
+}
+
+static int tce_iommu_attach_group(void *iommu_data,
+		struct iommu_group *iommu_group)
+{
+	struct tce_container *container = iommu_data;
+	struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
+
+	BUG_ON(!tbl);
+	mutex_lock(&container->lock);
+	pr_debug("tce_vfio: Attaching group #%u to iommu %p\n",
+			iommu_group_id(iommu_group), iommu_group);
+	if (container->tbl) {
+		pr_warn("tce_vfio: Only one group per IOMMU container is allowed, existing id=%d, attaching id=%d\n",
+				iommu_group_id(container->tbl->it_group),
+				iommu_group_id(iommu_group));
+		mutex_unlock(&container->lock);
+		return -EBUSY;
+	}
+
+	container->tbl = tbl;
+	iommu_reset_table(tbl, false);
+	mutex_unlock(&container->lock);
+
+	return 0;
+}
+
+static void tce_iommu_detach_group(void *iommu_data,
+		struct iommu_group *iommu_group)
+{
+	struct tce_container *container = iommu_data;
+	struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
+
+	BUG_ON(!tbl);
+	mutex_lock(&container->lock);
+	if (tbl != container->tbl) {
+		pr_warn("tce_vfio: detaching group #%u, expected group is #%u\n",
+				iommu_group_id(iommu_group),
+				iommu_group_id(tbl->it_group));
+	} else {
+
+		pr_debug("tce_vfio: detaching group #%u from iommu %p\n",
+				iommu_group_id(iommu_group), iommu_group);
+
+		container->tbl = NULL;
+		iommu_reset_table(tbl, true);
+	}
+	mutex_unlock(&container->lock);
+}
+
+const struct vfio_iommu_driver_ops tce_iommu_driver_ops = {
+	.name		= "iommu-vfio-powerpc",
+	.owner		= THIS_MODULE,
+	.open		= tce_iommu_open,
+	.release	= tce_iommu_release,
+	.ioctl		= tce_iommu_ioctl,
+	.attach_group	= tce_iommu_attach_group,
+	.detach_group	= tce_iommu_detach_group,
+};
+
+static int __init tce_iommu_init(void)
+{
+	return vfio_register_iommu_driver(&tce_iommu_driver_ops);
+}
+
+static void __exit tce_iommu_cleanup(void)
+{
+	vfio_unregister_iommu_driver(&tce_iommu_driver_ops);
+}
+
+module_init(tce_iommu_init);
+module_exit(tce_iommu_cleanup);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index 0a4f180..23cfc79 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -99,6 +99,7 @@ extern void vfio_unregister_iommu_driver(
 /* Extensions */
 
 #define VFIO_TYPE1_IOMMU		1
+#define VFIO_SPAPR_TCE_IOMMU		2
 
 /*
  * The IOCTL interface is designed for extensibility by embedding the
@@ -442,4 +443,33 @@ struct vfio_iommu_type1_dma_unmap {
 
 #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
 
+/* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */
+
+/*
+ * The SPAPR TCE info struct provides the information about the PCI bus
+ * address ranges available for DMA, these values are programmed into
+ * the hardware so the guest has to know that information.
+ *
+ * The DMA 32 bit window start is an absolute PCI bus address.
+ * The IOVA address passed via map/unmap ioctls are absolute PCI bus
+ * addresses too so the window works as a filter rather than an offset
+ * for IOVA addresses.
+ *
+ * At the momen the IOMMU page size is 4K.
+ */
+struct vfio_iommu_spapr_tce_info {
+	__u32 argsz;
+	__u32 flags;			/* reserved for future use */
+	__u32 dma32_window_start;	/* 32 bit window start (bytes) */
+	__u32 dma32_window_size;	/* 32 bit window size (bytes) */
+};
+
+#define VFIO_IOMMU_SPAPR_TCE_GET_INFO	_IO(VFIO_TYPE, VFIO_BASE + 12)
+
+/* Reuse type1 map/unmap structs as they are the same at the moment */
+typedef struct vfio_iommu_type1_dma_map vfio_iommu_spapr_tce_dma_map;
+typedef struct vfio_iommu_type1_dma_unmap vfio_iommu_spapr_tce_dma_unmap;
+
+/* ***************************************************************** */
+
 #endif /* VFIO_H */
-- 
1.7.10.4

^ permalink raw reply related

* Re: [Patch v4 09/12] memory-hotplug: remove page table of x86_64 architecture
From: Jianguo Wu @ 2012-12-07  7:06 UTC (permalink / raw)
  To: Tang Chen
  Cc: linux-ia64, linux-sh, linux-mm, paulus, sparclinux,
	Christoph Lameter, linux-s390, x86, linux-acpi, Yasuaki Ishimatsu,
	KOSAKI Motohiro, David Rientjes, Jiang Liu, Len Brown, Jiang Liu,
	Wen Congyang, cmetcalf, linux-kernel, Minchan Kim, Andrew Morton,
	linuxppc-dev
In-Reply-To: <50C19022.9000501@cn.fujitsu.com>

On 2012/12/7 14:43, Tang Chen wrote:

> On 11/27/2012 06:00 PM, Wen Congyang wrote:
>> For hot removing memory, we sholud remove page table about the memory.
>> So the patch searches a page table about the removed memory, and clear
>> page table.
> 
> (snip)
> 
>> +void __meminit
>> +kernel_physical_mapping_remove(unsigned long start, unsigned long end)
>> +{
>> +    unsigned long next;
>> +    bool pgd_changed = false;
>> +
>> +    start = (unsigned long)__va(start);
>> +    end = (unsigned long)__va(end);
> 
> Hi Wu,
> 
> Here, you expect start and end are physical addresses. But in
> phys_xxx_remove() function, I think using virtual addresses is just
> fine. Functions like pmd_addr_end() and pud_index() only calculate
> an offset.
>

Hi Tang,

 

Virtual addresses will work fine, I used physical addresses in order to
keep consistent with phys_pud[pmd/pte]_init(), So I think we should keep this.

Thanks,
Jianguo Wu

> So, would you please tell me if we have to use physical addresses here ?
> 
> Thanks. :)
> 
>> +
>> +    for (; start<  end; start = next) {
>> +        pgd_t *pgd = pgd_offset_k(start);
>> +        pud_t *pud;
>> +
>> +        next = pgd_addr_end(start, end);
>> +
>> +        if (!pgd_present(*pgd))
>> +            continue;
>> +
>> +        pud = map_low_page((pud_t *)pgd_page_vaddr(*pgd));
>> +        phys_pud_remove(pud, __pa(start), __pa(next));
>> +        if (free_pud_table(pud, pgd))
>> +            pgd_changed = true;
>> +        unmap_low_page(pud);
>> +    }
>> +
>> +    if (pgd_changed)
>> +        sync_global_pgds(start, end - 1);
>> +
>> +    flush_tlb_all();
>> +}
>> +
>>   #ifdef CONFIG_MEMORY_HOTREMOVE
>>   int __ref arch_remove_memory(u64 start, u64 size)
>>   {
>> @@ -692,6 +921,8 @@ int __ref arch_remove_memory(u64 start, u64 size)
>>       ret = __remove_pages(zone, start_pfn, nr_pages);
>>       WARN_ON_ONCE(ret);
>>
>> +    kernel_physical_mapping_remove(start, start + size);
>> +
>>       return ret;
>>   }
>>   #endif
> 
> 
> 
> .
> 

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox