[PATCH 1/4] powerpc: consolidate feature fixup code
Olof Johansson
olof at lixom.net
Thu Oct 12 23:56:17 EST 2006
On Thu, 12 Oct 2006 18:29:53 +1000 Benjamin Herrenschmidt <benh at kernel.crashing.org> wrote:
> There are currently two versions of the functions for applying the
> feature fixups, one for CPU features and one for firmware features. In
> addition, they are both in assembly.
>
> This patch replaces them with a single C function. The call site is
> slightly moved on ppc64 as well to be called from C instead of from
> assembly, though it's a very small move, and thus shouldn't cause any
> problem (called at the start of setup_system() instead of just before
> calling it).
>
> Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
>
>
> Index: linux-cell/arch/powerpc/kernel/head_64.S
> ===================================================================
> --- linux-cell.orig/arch/powerpc/kernel/head_64.S 2006-10-12 14:24:10.000000000 +1000
> +++ linux-cell/arch/powerpc/kernel/head_64.S 2006-10-12 14:24:54.000000000 +1000
> @@ -2000,13 +2000,6 @@ _STATIC(start_here_common)
> li r0,0
> stdu r0,-STACK_FRAME_OVERHEAD(r1)
>
> - /* Apply the CPUs-specific fixups (nop out sections not relevant
> - * to this CPU
> - */
> - li r3,0
> - bl .do_cpu_ftr_fixups
> - bl .do_fw_ftr_fixups
> -
> /* ptr to current */
> LOAD_REG_IMMEDIATE(r4, init_task)
> std r4,PACACURRENT(r13)
> Index: linux-cell/arch/powerpc/kernel/misc_64.S
> ===================================================================
> --- linux-cell.orig/arch/powerpc/kernel/misc_64.S 2006-10-12 14:24:10.000000000 +1000
> +++ linux-cell/arch/powerpc/kernel/misc_64.S 2006-10-12 14:24:54.000000000 +1000
> @@ -277,99 +277,6 @@ _GLOBAL(identify_cpu)
> mr r3,r5
> bctr
>
> -/*
> - * do_cpu_ftr_fixups - goes through the list of CPU feature fixups
> - * and writes nop's over sections of code that don't apply for this cpu.
> - * r3 = data offset (not changed)
> - */
> -_GLOBAL(do_cpu_ftr_fixups)
> - /* Get CPU 0 features */
> - LOAD_REG_IMMEDIATE(r6,cur_cpu_spec)
> - sub r6,r6,r3
> - ld r4,0(r6)
> - sub r4,r4,r3
> - ld r4,CPU_SPEC_FEATURES(r4)
> - /* Get the fixup table */
> - LOAD_REG_IMMEDIATE(r6,__start___ftr_fixup)
> - sub r6,r6,r3
> - LOAD_REG_IMMEDIATE(r7,__stop___ftr_fixup)
> - sub r7,r7,r3
> - /* Do the fixup */
> -1: cmpld r6,r7
> - bgelr
> - addi r6,r6,32
> - ld r8,-32(r6) /* mask */
> - and r8,r8,r4
> - ld r9,-24(r6) /* value */
> - cmpld r8,r9
> - beq 1b
> - ld r8,-16(r6) /* section begin */
> - ld r9,-8(r6) /* section end */
> - subf. r9,r8,r9
> - beq 1b
> - /* write nops over the section of code */
> - /* todo: if large section, add a branch at the start of it */
> - srwi r9,r9,2
> - mtctr r9
> - sub r8,r8,r3
> - lis r0,0x60000000 at h /* nop */
> -3: stw r0,0(r8)
> - andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE at l
> - beq 2f
> - dcbst 0,r8 /* suboptimal, but simpler */
> - sync
> - icbi 0,r8
> -2: addi r8,r8,4
> - bdnz 3b
> - sync /* additional sync needed on g4 */
> - isync
> - b 1b
> -
> -/*
> - * do_fw_ftr_fixups - goes through the list of firmware feature fixups
> - * and writes nop's over sections of code that don't apply for this firmware.
> - * r3 = data offset (not changed)
> - */
> -_GLOBAL(do_fw_ftr_fixups)
> - /* Get firmware features */
> - LOAD_REG_IMMEDIATE(r6,powerpc_firmware_features)
> - sub r6,r6,r3
> - ld r4,0(r6)
> - /* Get the fixup table */
> - LOAD_REG_IMMEDIATE(r6,__start___fw_ftr_fixup)
> - sub r6,r6,r3
> - LOAD_REG_IMMEDIATE(r7,__stop___fw_ftr_fixup)
> - sub r7,r7,r3
> - /* Do the fixup */
> -1: cmpld r6,r7
> - bgelr
> - addi r6,r6,32
> - ld r8,-32(r6) /* mask */
> - and r8,r8,r4
> - ld r9,-24(r6) /* value */
> - cmpld r8,r9
> - beq 1b
> - ld r8,-16(r6) /* section begin */
> - ld r9,-8(r6) /* section end */
> - subf. r9,r8,r9
> - beq 1b
> - /* write nops over the section of code */
> - /* todo: if large section, add a branch at the start of it */
> - srwi r9,r9,2
> - mtctr r9
> - sub r8,r8,r3
> - lis r0,0x60000000 at h /* nop */
> -3: stw r0,0(r8)
> -BEGIN_FTR_SECTION
> - dcbst 0,r8 /* suboptimal, but simpler */
> - sync
> - icbi 0,r8
> -END_FTR_SECTION_IFSET(CPU_FTR_SPLIT_ID_CACHE)
> - addi r8,r8,4
> - bdnz 3b
> - sync /* additional sync needed on g4 */
> - isync
> - b 1b
>
> #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
> /*
> Index: linux-cell/arch/powerpc/kernel/setup-common.c
> ===================================================================
> --- linux-cell.orig/arch/powerpc/kernel/setup-common.c 2006-10-12 14:24:10.000000000 +1000
> +++ linux-cell/arch/powerpc/kernel/setup-common.c 2006-10-12 17:46:02.000000000 +1000
> @@ -520,3 +520,32 @@ void __init setup_panic(void)
> {
> atomic_notifier_chain_register(&panic_notifier_list, &ppc_panic_block);
> }
> +
> +void do_feature_fixups(unsigned long offset, unsigned long value,
> + void *fixup_start, void *fixup_end)
> +{
> + struct fixup_entry {
> + unsigned long mask;
> + unsigned long value;
> + unsigned int *start;
> + unsigned int *end;
> + } *fcur, *fend;
Shouldn't there be a better place to keep this struct definition than
in the function it's used? Some header file?
> +
> + fcur = fixup_start;
> + fend = fixup_end;
> +
> + for (; fcur < fend; fcur++) {
for (fcur = fixup_start; fcur < fend; fcur++) {
> + unsigned int *pcur, *pend;
> +
> + if ((value & fcur->mask) == fcur->value)
> + continue;
> +
> + pcur = fcur->start - offset;
> + pend = fcur->end - offset;
> + for (; pcur < pend; pcur++) {
> + *pcur = 0x60000000u;
> + asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync"
> + : : "r" (pcur));
> + }
Ok, now it's in C, no reason to do a dcbst/icbi for every word. We did
it in asm for simplicity's sake. Split it in two loops, one to nop,
second to step per line and do the flushes. :-)
> + }
> +}
> Index: linux-cell/arch/powerpc/kernel/setup.h
> ===================================================================
> --- linux-cell.orig/arch/powerpc/kernel/setup.h 2006-10-12 14:24:10.000000000 +1000
> +++ linux-cell/arch/powerpc/kernel/setup.h 2006-10-12 17:46:02.000000000 +1000
> @@ -1,9 +1,12 @@
> #ifndef _POWERPC_KERNEL_SETUP_H
> #define _POWERPC_KERNEL_SETUP_H
>
> -void check_for_initrd(void);
> -void do_init_bootmem(void);
> -void setup_panic(void);
> +extern void check_for_initrd(void);
> +extern void do_init_bootmem(void);
> +extern void setup_panic(void);
> +extern void do_feature_fixups(unsigned long offset, unsigned long value,
> + void *fixup_start, void *fixup_end);
> +
> extern int do_early_xmon;
>
> #endif /* _POWERPC_KERNEL_SETUP_H */
> Index: linux-cell/arch/powerpc/kernel/setup_32.c
> ===================================================================
> --- linux-cell.orig/arch/powerpc/kernel/setup_32.c 2006-10-12 14:24:10.000000000 +1000
> +++ linux-cell/arch/powerpc/kernel/setup_32.c 2006-10-12 17:46:24.000000000 +1000
> @@ -90,6 +90,7 @@ int ucache_bsize;
> */
> unsigned long __init early_init(unsigned long dt_ptr)
> {
> + extern unsigned int __start___ftr_fixup, __stop___ftr_fixup;
> unsigned long offset = reloc_offset();
>
> /* First zero the BSS -- use memset_io, some platforms don't have
> @@ -101,7 +102,9 @@ unsigned long __init early_init(unsigned
> * that depend on which cpu we have.
> */
> identify_cpu(offset, 0);
> - do_cpu_ftr_fixups(offset);
> +
> + do_feature_fixups(offset, cur_cpu_spec->cpu_features,
> + &__start___ftr_fixup, &__stop___ftr_fixup);
>
> return KERNELBASE + offset;
> }
> Index: linux-cell/arch/powerpc/kernel/setup_64.c
> ===================================================================
> --- linux-cell.orig/arch/powerpc/kernel/setup_64.c 2006-10-12 14:24:10.000000000 +1000
> +++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-10-12 17:46:18.000000000 +1000
> @@ -346,8 +346,19 @@ static void __init initialize_cache_info
> */
> void __init setup_system(void)
> {
> + extern unsigned int __start___ftr_fixup, __stop___ftr_fixup;
> + extern unsigned int __start___fw_ftr_fixup, __stop___fw_ftr_fixup;
> +
> DBG(" -> setup_system()\n");
>
> + /* Apply the CPUs-specific and firmware specific fixups to kernel
> + * text (nop out sections not relevant to this CPU or this firmware)
> + */
> + do_feature_fixups(0, cur_cpu_spec->cpu_features,
> + &__start___ftr_fixup, &__stop___ftr_fixup);
> + do_feature_fixups(0, powerpc_firmware_features,
> + &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
> +
> /*
> * Unflatten the device-tree passed by prom_init or kexec
> */
>
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev at ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
More information about the Linuxppc-dev
mailing list