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

Commit e7bc15a9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: Fix memory leak when cpu hotplugging.
  [SPARC64]: Do not assume sun4v chips have load-twin/store-init support.
  [SPARC64]: Fix hard-coding of cpu type output in /proc/cpuinfo on sun4v.
  [SPARC]: Centralize find_in_proplist() instead of duplicating N times.
parents 5a0276b7 b434e719
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -102,6 +102,21 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
}
}
EXPORT_SYMBOL(of_set_property);
EXPORT_SYMBOL(of_set_property);


int of_find_in_proplist(const char *list, const char *match, int len)
{
	while (len > 0) {
		int l;

		if (!strcmp(list, match))
			return 1;
		l = strlen(list) + 1;
		list += l;
		len -= l;
	}
	return 0;
}
EXPORT_SYMBOL(of_find_in_proplist);

static unsigned int prom_early_allocated;
static unsigned int prom_early_allocated;


static void * __init prom_early_alloc(unsigned long size)
static void * __init prom_early_alloc(unsigned long size)
+28 −8
Original line number Original line Diff line number Diff line
/* cpu.c: Dinky routines to look for the kind of Sparc cpu
/* cpu.c: Dinky routines to look for the kind of Sparc cpu
 *        we are on.
 *        we are on.
 *
 *
 * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
 * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
 */
 */


#include <linux/kernel.h>
#include <linux/kernel.h>
@@ -13,6 +13,7 @@
#include <asm/fpumacro.h>
#include <asm/fpumacro.h>
#include <asm/cpudata.h>
#include <asm/cpudata.h>
#include <asm/spitfire.h>
#include <asm/spitfire.h>
#include <asm/oplib.h>


DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };


@@ -61,21 +62,40 @@ struct cpu_iu_info linux_sparc_chips[] = {


#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)
#define NSPARCCHIPS  ARRAY_SIZE(linux_sparc_chips)


char *sparc_cpu_type = "cpu-oops";
char *sparc_cpu_type;
char *sparc_fpu_type = "fpu-oops";
char *sparc_fpu_type;


unsigned int fsr_storage;
unsigned int fsr_storage;


static void __init sun4v_cpu_probe(void)
{
	switch (sun4v_chip_type) {
	case SUN4V_CHIP_NIAGARA1:
		sparc_cpu_type = "UltraSparc T1 (Niagara)";
		sparc_fpu_type = "UltraSparc T1 integrated FPU";
		break;

	case SUN4V_CHIP_NIAGARA2:
		sparc_cpu_type = "UltraSparc T2 (Niagara2)";
		sparc_fpu_type = "UltraSparc T2 integrated FPU";
		break;

	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)
void __init cpu_probe(void)
{
{
	unsigned long ver, fpu_vers, manuf, impl, fprs;
	unsigned long ver, fpu_vers, manuf, impl, fprs;
	int i;
	int i;
	
	
	if (tlb_type == hypervisor) {
	if (tlb_type == hypervisor)
		sparc_cpu_type = "UltraSparc T1 (Niagara)";
		return sun4v_cpu_probe();
		sparc_fpu_type = "UltraSparc T1 integrated FPU";
		return;
	}


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


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


	sethi	%hi(is_sun4v), %g1
	sethi	%hi(is_sun4v), %g1
@@ -310,7 +319,80 @@ is_sun4v:
	mov	1, %g7
	mov	1, %g7
	stw	%g7, [%g1]
	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_SUN4V(g1, jump_to_sun4u_init)
	BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
	BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
	BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_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)]
	stw	%g2, [%g1 + %lo(tlb_type)]


	/* Patch copy/clear ops.  */
	/* 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
	call	niagara_patch_copyops
	 nop
	 nop
	call	niagara_patch_bzero
	call	niagara_patch_bzero
@@ -421,6 +521,7 @@ niagara_tlb_fixup:
	call	niagara_patch_pageops
	call	niagara_patch_pageops
	 nop
	 nop


80:
	/* Patch TLB/cache ops.  */
	/* Patch TLB/cache ops.  */
	call	hypervisor_patch_cachetlbops
	call	hypervisor_patch_cachetlbops
	 nop
	 nop
+2 −5
Original line number Original line Diff line number Diff line
@@ -115,11 +115,8 @@ hv_cpu_startup:
	call		hard_smp_processor_id
	call		hard_smp_processor_id
	 nop
	 nop


	mov		%o0, %o1
	call		sun4v_register_mondo_queues
	mov		0, %o0
	 nop
	mov		0, %o2
	call		sun4v_init_mondo_queues
	 mov		1, %o3


	call		init_cur_cpu_trap
	call		init_cur_cpu_trap
	 mov		%g6, %o0
	 mov		%g6, %o0
+24 −50
Original line number Original line Diff line number Diff line
@@ -929,7 +929,7 @@ static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type
	}
	}
}
}


static void __cpuinit sun4v_register_mondo_queues(int this_cpu)
void __cpuinit sun4v_register_mondo_queues(int this_cpu)
{
{
	struct trap_per_cpu *tb = &trap_block[this_cpu];
	struct trap_per_cpu *tb = &trap_block[this_cpu];


@@ -943,20 +943,10 @@ static void __cpuinit sun4v_register_mondo_queues(int this_cpu)
			   tb->nonresum_qmask);
			   tb->nonresum_qmask);
}
}


static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem)
static void __init alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask)
{
{
	unsigned long size = PAGE_ALIGN(qmask + 1);
	unsigned long size = PAGE_ALIGN(qmask + 1);
	unsigned long order = get_order(size);
	void *p = __alloc_bootmem_low(size, size, 0);
	void *p = NULL;

	if (use_bootmem) {
		p = __alloc_bootmem_low(size, size, 0);
	} else {
		struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order);
		if (page)
			p = page_address(page);
	}

	if (!p) {
	if (!p) {
		prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
		prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
		prom_halt();
		prom_halt();
@@ -965,19 +955,10 @@ static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask
	*pa_ptr = __pa(p);
	*pa_ptr = __pa(p);
}
}


static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem)
static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask)
{
{
	unsigned long size = PAGE_ALIGN(qmask + 1);
	unsigned long size = PAGE_ALIGN(qmask + 1);
	unsigned long order = get_order(size);
	void *p = __alloc_bootmem_low(size, size, 0);
	void *p = NULL;

	if (use_bootmem) {
		p = __alloc_bootmem_low(size, size, 0);
	} else {
		struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order);
		if (page)
			p = page_address(page);
	}


	if (!p) {
	if (!p) {
		prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
		prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
@@ -987,18 +968,14 @@ static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask,
	*pa_ptr = __pa(p);
	*pa_ptr = __pa(p);
}
}


static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem)
static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb)
{
{
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	void *page;
	void *page;


	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
	BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));


	if (use_bootmem)
	page = alloc_bootmem_low_pages(PAGE_SIZE);
	page = alloc_bootmem_low_pages(PAGE_SIZE);
	else
		page = (void *) get_zeroed_page(GFP_ATOMIC);

	if (!page) {
	if (!page) {
		prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
		prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
		prom_halt();
		prom_halt();
@@ -1009,30 +986,27 @@ static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_
#endif
#endif
}
}


/* Allocate and register the mondo and error queues for this cpu.  */
/* Allocate mondo and error queues for all possible cpus.  */
void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load)
static void __init sun4v_init_mondo_queues(void)
{
{
	int cpu;

	for_each_possible_cpu(cpu) {
		struct trap_per_cpu *tb = &trap_block[cpu];
		struct trap_per_cpu *tb = &trap_block[cpu];


	if (alloc) {
		alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask);
		alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask, use_bootmem);
		alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask);
		alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask, use_bootmem);
		alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask);
		alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask, use_bootmem);
		alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask);
		alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask, use_bootmem);
		alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask);
		alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask, use_bootmem);
		alloc_one_kbuf(&tb->nonresum_kernel_buf_pa,
		alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask, use_bootmem);
			       tb->nonresum_qmask);


		init_cpu_send_mondo_info(tb, use_bootmem);
		init_cpu_send_mondo_info(tb);
	}
	}


	if (load) {
	/* Load up the boot cpu's entries.  */
		if (cpu != hard_smp_processor_id()) {
	sun4v_register_mondo_queues(hard_smp_processor_id());
			prom_printf("SUN4V: init mondo on cpu %d not %d\n",
				    cpu, hard_smp_processor_id());
			prom_halt();
		}
		sun4v_register_mondo_queues(cpu);
	}
}
}


static struct irqaction timer_irq_action = {
static struct irqaction timer_irq_action = {
@@ -1047,7 +1021,7 @@ void __init init_IRQ(void)
	memset(&ivector_table[0], 0, sizeof(ivector_table));
	memset(&ivector_table[0], 0, sizeof(ivector_table));


	if (tlb_type == hypervisor)
	if (tlb_type == hypervisor)
		sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1);
		sun4v_init_mondo_queues();


	/* We need to clear any IRQ's pending in the soft interrupt
	/* We need to clear any IRQ's pending in the soft interrupt
	 * registers, a spurious one could be left around from the
	 * registers, a spurious one could be left around from the
Loading