Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c70b6fc authored by David S. Miller's avatar David S. Miller
Browse files

[SPARC64]: Do not assume sun4v chips have load-twin/store-init support.



Check the cpu type in the OBP device tree before committing to
using the optimized Niagara memcpy and memset implementation.

If we don't recognize the cpu type, use a completely generic
version.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 68c9f9fd
Loading
Loading
Loading
Loading
+15 −27
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@
#include <asm/fpumacro.h>
#include <asm/cpudata.h>
#include <asm/spitfire.h>
#include <asm/prom.h>
#include <asm/oplib.h>

DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };

@@ -69,36 +69,24 @@ unsigned int fsr_storage;

static void __init sun4v_cpu_probe(void)
{
	struct device_node *dp;
	const char *compat;
	int len;

	dp = of_find_node_by_name(NULL, "cpu");
	if (!dp)
		goto no_compat;

	compat = of_get_property(dp, "compatible", &len);
	if (!compat)
		goto no_compat;

	if (of_find_in_proplist(compat, "SUNW,UltraSPARC-T1", len)) {
	switch (sun4v_chip_type) {
	case SUN4V_CHIP_NIAGARA1:
		sparc_cpu_type = "UltraSparc T1 (Niagara)";
		sparc_fpu_type = "UltraSparc T1 integrated FPU";
	} else if (of_find_in_proplist(compat, "SUNW,UltraSPARC-T2", len)) {
		break;

	case SUN4V_CHIP_NIAGARA2:
		sparc_cpu_type = "UltraSparc T2 (Niagara2)";
		sparc_fpu_type = "UltraSparc T2 integrated FPU";
	} else
		goto unknown;

	return;

no_compat:
	compat = "no property";
		break;

unknown:
	printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n", compat);
	default:
		printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
		       prom_cpu_compatible);
		sparc_cpu_type = "Unknown SUN4V CPU";
		sparc_fpu_type = "Unknown SUN4V FPU";
		break;
	}
}

void __init cpu_probe(void)
+106 −5
Original line number Diff line number Diff line
@@ -97,7 +97,8 @@ sparc64_boot:
	.globl	prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache
	.globl	prom_boot_mapped_pc, prom_boot_mapping_mode
	.globl	prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
	.globl	is_sun4v
	.globl	prom_compatible_name, prom_cpu_path, prom_cpu_compatible
	.globl	is_sun4v, sun4v_chip_type
prom_peer_name:
	.asciz	"peer"
prom_compatible_name:
@@ -106,6 +107,8 @@ prom_finddev_name:
	.asciz	"finddevice"
prom_chosen_path:
	.asciz	"/chosen"
prom_cpu_path:
	.asciz	"/cpu"
prom_getprop_name:
	.asciz	"getprop"
prom_mmu_name:
@@ -120,9 +123,13 @@ prom_unmap_name:
	.asciz	"unmap"
prom_sun4v_name:
	.asciz	"sun4v"
prom_niagara_prefix:
	.asciz	"SUNW,UltraSPARC-T"
	.align	4
prom_root_compatible:
	.skip	64
prom_cpu_compatible:
	.skip	64
prom_root_node:
	.word	0
prom_mmu_ihandle_cache:
@@ -138,6 +145,8 @@ prom_boot_mapping_phys_low:
	.xword	0
is_sun4v:
	.word	0
sun4v_chip_type:
	.word	SUN4V_CHIP_INVALID
1:
	rd	%pc, %l0

@@ -296,13 +305,13 @@ is_sun4v:
	sethi	%hi(prom_sun4v_name), %g7
	or	%g7, %lo(prom_sun4v_name), %g7
	mov	5, %g3
1:	ldub	[%g7], %g2
90:	ldub	[%g7], %g2
	ldub	[%g1], %g4
	cmp	%g2, %g4
	bne,pn	%icc, 2f
	bne,pn	%icc, 80f
	 add	%g7, 1, %g7
	subcc	%g3, 1, %g3
	bne,pt	%xcc, 1b
	bne,pt	%xcc, 90b
	 add	%g1, 1, %g1

	sethi	%hi(is_sun4v), %g1
@@ -310,7 +319,80 @@ is_sun4v:
	mov	1, %g7
	stw	%g7, [%g1]

2:
	/* cpu_node = prom_finddevice("/cpu") */
	mov	(1b - prom_finddev_name), %l1
	mov	(1b - prom_cpu_path), %l2
	sub	%l0, %l1, %l1
	sub	%l0, %l2, %l2
	sub	%sp, (192 + 128), %sp

	stx	%l1, [%sp + 2047 + 128 + 0x00]	! service, "finddevice"
	mov	1, %l3
	stx	%l3, [%sp + 2047 + 128 + 0x08]	! num_args, 1
	stx	%l3, [%sp + 2047 + 128 + 0x10]	! num_rets, 1
	stx	%l2, [%sp + 2047 + 128 + 0x18]	! arg1, "/cpu"
	stx	%g0, [%sp + 2047 + 128 + 0x20]	! ret1
	call	%l7
	 add	%sp, (2047 + 128), %o0		! argument array

	ldx	[%sp + 2047 + 128 + 0x20], %l4	! cpu device node

	mov	(1b - prom_getprop_name), %l1
	mov	(1b - prom_compatible_name), %l2
	mov	(1b - prom_cpu_compatible), %l5
	sub	%l0, %l1, %l1
	sub	%l0, %l2, %l2
	sub	%l0, %l5, %l5

	/* prom_getproperty(cpu_node, "compatible",
	 *                  &prom_cpu_compatible, 64)
	 */
	stx	%l1, [%sp + 2047 + 128 + 0x00]	! service, "getprop"
	mov	4, %l3
	stx	%l3, [%sp + 2047 + 128 + 0x08]	! num_args, 4
	mov	1, %l3
	stx	%l3, [%sp + 2047 + 128 + 0x10]	! num_rets, 1
	stx	%l4, [%sp + 2047 + 128 + 0x18]	! arg1, cpu_node
	stx	%l2, [%sp + 2047 + 128 + 0x20]	! arg2, "compatible"
	stx	%l5, [%sp + 2047 + 128 + 0x28]	! arg3, &prom_cpu_compatible
	mov	64, %l3
	stx	%l3, [%sp + 2047 + 128 + 0x30]	! arg4, size
	stx	%g0, [%sp + 2047 + 128 + 0x38]	! ret1
	call	%l7
	 add	%sp, (2047 + 128), %o0		! argument array

	add	%sp, (192 + 128), %sp

	sethi	%hi(prom_cpu_compatible), %g1
	or	%g1, %lo(prom_cpu_compatible), %g1
	sethi	%hi(prom_niagara_prefix), %g7
	or	%g7, %lo(prom_niagara_prefix), %g7
	mov	17, %g3
90:	ldub	[%g7], %g2
	ldub	[%g1], %g4
	cmp	%g2, %g4
	bne,pn	%icc, 4f
	 add	%g7, 1, %g7
	subcc	%g3, 1, %g3
	bne,pt	%xcc, 90b
	 add	%g1, 1, %g1

	sethi	%hi(prom_cpu_compatible), %g1
	or	%g1, %lo(prom_cpu_compatible), %g1
	ldub	[%g1 + 17], %g2
	cmp	%g2, '1'
	be,pt	%xcc, 5f
	 mov	SUN4V_CHIP_NIAGARA1, %g4
	cmp	%g2, '2'
	be,pt	%xcc, 5f
	 mov	SUN4V_CHIP_NIAGARA2, %g4
4:
	mov	SUN4V_CHIP_UNKNOWN, %g4
5:	sethi	%hi(sun4v_chip_type), %g2
	or	%g2, %lo(sun4v_chip_type), %g2
	stw	%g4, [%g2]

80:
	BRANCH_IF_SUN4V(g1, jump_to_sun4u_init)
	BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot)
@@ -414,6 +496,24 @@ niagara_tlb_fixup:
	stw	%g2, [%g1 + %lo(tlb_type)]

	/* Patch copy/clear ops.  */
	sethi	%hi(sun4v_chip_type), %g1
	lduw	[%g1 + %lo(sun4v_chip_type)], %g1
	cmp	%g1, SUN4V_CHIP_NIAGARA1
	be,pt	%xcc, niagara_patch
	 cmp	%g1, SUN4V_CHIP_NIAGARA2
	be,pt	%xcc, niagara_patch
	 nop

	call	generic_patch_copyops
	 nop
	call	generic_patch_bzero
	 nop
	call	generic_patch_pageops
	 nop

	ba,a,pt	%xcc, 80f

niagara_patch:
	call	niagara_patch_copyops
	 nop
	call	niagara_patch_bzero
@@ -421,6 +521,7 @@ niagara_tlb_fixup:
	call	niagara_patch_pageops
	 nop

80:
	/* Patch TLB/cache ops.  */
	call	hypervisor_patch_cachetlbops
	 nop
+1 −0
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ EXPORT_SYMBOL(change_bit);
EXPORT_SYMBOL(__flushw_user);

EXPORT_SYMBOL(tlb_type);
EXPORT_SYMBOL(sun4v_chip_type);
EXPORT_SYMBOL(get_fb_unmapped_area);
EXPORT_SYMBOL(flush_icache_range);

+160 −0
Original line number Diff line number Diff line
/* GENbzero.S: Generic sparc64 memset/clear_user.
 *
 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
 */
#include <asm/asi.h>

#define EX_ST(x,y)		\
98:	x,y;			\
	.section .fixup;	\
	.align 4;		\
99:	retl;			\
	 mov	%o1, %o0;	\
	.section __ex_table;	\
	.align 4;		\
	.word 98b, 99b;		\
	.text;			\
	.align 4;

	.align	32
	.text

	.globl		GENmemset
	.type		GENmemset, #function
GENmemset:		/* %o0=buf, %o1=pat, %o2=len */
	and		%o1, 0xff, %o3
	mov		%o2, %o1
	sllx		%o3, 8, %g1
	or		%g1, %o3, %o2
	sllx		%o2, 16, %g1
	or		%g1, %o2, %o2
	sllx		%o2, 32, %g1
	ba,pt		%xcc, 1f
	 or		%g1, %o2, %o2

	.globl		GENbzero
	.type		GENbzero, #function
GENbzero:
	clr		%o2
1:	brz,pn		%o1, GENbzero_return
	 mov		%o0, %o3

	/* %o5: saved %asi, restored at GENbzero_done
	 * %o4:	store %asi to use
	 */
	rd		%asi, %o5
	mov		ASI_P, %o4
	wr		%o4, 0x0, %asi

GENbzero_from_clear_user:
	cmp		%o1, 15
	bl,pn		%icc, GENbzero_tiny
	 andcc		%o0, 0x7, %g1
	be,pt		%xcc, 2f
	 mov		8, %g2
	sub		%g2, %g1, %g1
	sub		%o1, %g1, %o1
1:	EX_ST(stba %o2, [%o0 + 0x00] %asi)
	subcc		%g1, 1, %g1
	bne,pt		%xcc, 1b
	 add		%o0, 1, %o0
2:	cmp		%o1, 128
	bl,pn		%icc, GENbzero_medium
	 andcc		%o0, (64 - 1), %g1
	be,pt		%xcc, GENbzero_pre_loop
	 mov		64, %g2
	sub		%g2, %g1, %g1
	sub		%o1, %g1, %o1
1:	EX_ST(stxa %o2, [%o0 + 0x00] %asi)
	subcc		%g1, 8, %g1
	bne,pt		%xcc, 1b
	 add		%o0, 8, %o0

GENbzero_pre_loop:
	andn		%o1, (64 - 1), %g1
	sub		%o1, %g1, %o1
GENbzero_loop:
	EX_ST(stxa %o2, [%o0 + 0x00] %asi)
	EX_ST(stxa %o2, [%o0 + 0x08] %asi)
	EX_ST(stxa %o2, [%o0 + 0x10] %asi)
	EX_ST(stxa %o2, [%o0 + 0x18] %asi)
	EX_ST(stxa %o2, [%o0 + 0x20] %asi)
	EX_ST(stxa %o2, [%o0 + 0x28] %asi)
	EX_ST(stxa %o2, [%o0 + 0x30] %asi)
	EX_ST(stxa %o2, [%o0 + 0x38] %asi)
	subcc		%g1, 64, %g1
	bne,pt		%xcc, GENbzero_loop
	 add		%o0, 64, %o0

	membar		#Sync
	wr		%o4, 0x0, %asi
	brz,pn		%o1, GENbzero_done
GENbzero_medium:
	 andncc		%o1, 0x7, %g1
	be,pn		%xcc, 2f
	 sub		%o1, %g1, %o1
1:	EX_ST(stxa %o2, [%o0 + 0x00] %asi)
	subcc		%g1, 8, %g1
	bne,pt		%xcc, 1b
	 add		%o0, 8, %o0
2:	brz,pt		%o1, GENbzero_done
	 nop

GENbzero_tiny:
1:	EX_ST(stba %o2, [%o0 + 0x00] %asi)
	subcc		%o1, 1, %o1
	bne,pt		%icc, 1b
	 add		%o0, 1, %o0

	/* fallthrough */

GENbzero_done:
	wr		%o5, 0x0, %asi

GENbzero_return:
	retl
	 mov		%o3, %o0
	.size		GENbzero, .-GENbzero
	.size		GENmemset, .-GENmemset

	.globl		GENclear_user
	.type		GENclear_user, #function
GENclear_user:		/* %o0=buf, %o1=len */
	rd		%asi, %o5
	brz,pn		%o1, GENbzero_done
	 clr		%o3
	cmp		%o5, ASI_AIUS
	bne,pn		%icc, GENbzero
	 clr		%o2
	ba,pt		%xcc, GENbzero_from_clear_user
	 mov		ASI_AIUS, %o4
	.size		GENclear_user, .-GENclear_user

#define BRANCH_ALWAYS	0x10680000
#define NOP		0x01000000
#define GEN_DO_PATCH(OLD, NEW)	\
	sethi	%hi(NEW), %g1; \
	or	%g1, %lo(NEW), %g1; \
	sethi	%hi(OLD), %g2; \
	or	%g2, %lo(OLD), %g2; \
	sub	%g1, %g2, %g1; \
	sethi	%hi(BRANCH_ALWAYS), %g3; \
	sll	%g1, 11, %g1; \
	srl	%g1, 11 + 2, %g1; \
	or	%g3, %lo(BRANCH_ALWAYS), %g3; \
	or	%g3, %g1, %g3; \
	stw	%g3, [%g2]; \
	sethi	%hi(NOP), %g3; \
	or	%g3, %lo(NOP), %g3; \
	stw	%g3, [%g2 + 0x4]; \
	flush	%g2;

	.globl	generic_patch_bzero
	.type	generic_patch_bzero,#function
generic_patch_bzero:
	GEN_DO_PATCH(memset, GENmemset)
	GEN_DO_PATCH(__bzero, GENbzero)
	GEN_DO_PATCH(__clear_user, GENclear_user)
	retl
	 nop
	.size	generic_patch_bzero,.-generic_patch_bzero
+34 −0
Original line number Diff line number Diff line
/* GENcopy_from_user.S: Generic sparc64 copy from userspace.
 *
 * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
 */

#define EX_LD(x)		\
98:	x;			\
	.section .fixup;	\
	.align 4;		\
99:	retl;			\
	 mov	1, %o0;		\
	.section __ex_table,"a";\
	.align 4;		\
	.word 98b, 99b;		\
	.text;			\
	.align 4;

#ifndef ASI_AIUS
#define ASI_AIUS	0x11
#endif

#define FUNC_NAME		GENcopy_from_user
#define LOAD(type,addr,dest)	type##a [addr] ASI_AIUS, dest
#define EX_RETVAL(x)		0

#ifdef __KERNEL__
#define PREAMBLE					\
	rd		%asi, %g1;			\
	cmp		%g1, ASI_AIUS;			\
	bne,pn		%icc, memcpy_user_stub;		\
	 nop
#endif

#include "GENmemcpy.S"
Loading