* Xilinx I2C driver for linux 2.6?
From: Jean-Baptiste Maneyrol @ 2006-10-12 14:35 UTC (permalink / raw)
To: linuxppc-embedded
Hi everybody!
Does anyone know if there is somewhere an i2c driver for the Xilinx IIC IP
working on linux 2.6?
I'm using the ML405 board with EDK 8.2i, and their driver is for linux 2.4.
Thanks!
Jean-Baptiste Maneyrol
Teamlog - France
________________________________________________
Message sent using UebiMiau 2.7.9
^ permalink raw reply
* Re: [PATCH 4/4] powerpc: Cell timebase workaround
From: Olof Johansson @ 2006-10-12 14:14 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1160641804.4792.136.camel@localhost.localdomain>
On Thu, 12 Oct 2006 18:30:04 +1000 Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
> The Cell CPU timebase has an errata. When reading the entire 64 bits of
> the timebase with one mftb instruction, there is a handful of cycles
> window during which one might read a value with the low order 32 bits
> already reset to 0x00000000 but the high order bits not yet incremeted
> by one. Simply reading the timebase a second time if the low order bits
> are 0 is enough (the second read will always miss that window).
>
> Note that there is still a potential issue if the process gets
> interrupted between the 2 reads for long enough that the second reads
> pricely hits that same window on the next 32 bits wrap. However, this is
> so extremely unlikely to happen that we choose not to do anything
> against it (the 32 bits wrap happens every few seconds or so, in fact
> every few minutes on IBM cell blades).
>
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>
> This is the "old" patch adapted to apply on top of the previous changes.
> I'll post tomorrow a new version of the patch using a different
> technique for the workaround
>
> Index: linux-cell/arch/powerpc/kernel/vdso64/gettimeofday.S
> ===================================================================
> --- linux-cell.orig/arch/powerpc/kernel/vdso64/gettimeofday.S 2006-10-12 18:08:40.000000000 +1000
> +++ linux-cell/arch/powerpc/kernel/vdso64/gettimeofday.S 2006-10-12 18:18:15.000000000 +1000
> @@ -11,6 +11,7 @@
> * as published by the Free Software Foundation; either version
> * 2 of the License, or (at your option) any later version.
> */
> +
> #include <asm/processor.h>
> #include <asm/ppc_asm.h>
> #include <asm/vdso.h>
> @@ -229,8 +230,13 @@ V_FUNCTION_BEGIN(__do_get_xsec)
> xor r0,r8,r8 /* create dependency */
> add r3,r3,r0
>
> - /* Get TB & offset it */
> - mftb r7
> + /* Get TB & offset it. We use the MFTB macro which will generate
> + * workaround code for Cell. The macro will generate the ELF bits
> + * for the CPU feature fixup though those aren't actually applied
> + * on the vDSO, which means that the workaround will always be
> + * executed if CONFIG_PPC_CELL is set.
> + */
> + MFTB(r7)
> ld r9,CFG_TB_ORIG_STAMP(r3)
> subf r7,r9,r7
>
> Index: linux-cell/include/asm-powerpc/cputable.h
> ===================================================================
> --- linux-cell.orig/include/asm-powerpc/cputable.h 2006-10-12 18:17:44.000000000 +1000
> +++ linux-cell/include/asm-powerpc/cputable.h 2006-10-12 18:18:15.000000000 +1000
> @@ -144,6 +144,7 @@ extern void do_cpu_ftr_fixups(unsigned l
> #define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000)
> #define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000)
> #define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000)
> +#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000)
>
> #ifndef __ASSEMBLY__
>
> @@ -332,7 +333,7 @@ extern void do_cpu_ftr_fixups(unsigned l
> #define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
> CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
> CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
> - CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE)
> + CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
> #define CPU_FTRS_PA6T (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
> CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
> CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
> Index: linux-cell/include/asm-powerpc/ppc_asm.h
> ===================================================================
> --- linux-cell.orig/include/asm-powerpc/ppc_asm.h 2006-10-12 18:08:40.000000000 +1000
> +++ linux-cell/include/asm-powerpc/ppc_asm.h 2006-10-12 18:18:15.000000000 +1000
> @@ -29,10 +29,10 @@
> BEGIN_FTR_SECTION; \
> mfspr ra,SPRN_PURR; /* get processor util. reg */ \
> END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
> -BEGIN_FTR_SECTION; \
> - mftb ra; /* or get TB if no PURR */ \
> -END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
> - ld rb,PACA_STARTPURR(r13); \
> +BEGIN_FTR_SECTION_NESTED(96); \
> + MFTB(ra); /* or get TB if no PURR */ \
> +END_FTR_SECTION_NESTED(CPU_FTR_PURR, 0, 96); \
> + ld rb,PACA_STARTPURR(r13); \
> std ra,PACA_STARTPURR(r13); \
> subf rb,rb,ra; /* subtract start value */ \
> ld ra,PACA_USER_TIME(r13); \
> @@ -44,9 +44,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_PURR);
> BEGIN_FTR_SECTION; \
> mfspr ra,SPRN_PURR; /* get processor util. reg */ \
> END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
> -BEGIN_FTR_SECTION; \
> - mftb ra; /* or get TB if no PURR */ \
> -END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
> +BEGIN_FTR_SECTION_NESTED(96); \
> + MFTB(ra); /* or get TB if no PURR */ \
> +END_FTR_SECTION_NESTED(CPU_FTR_PURR, 0, 96); \
> ld rb,PACA_STARTPURR(r13); \
> std ra,PACA_STARTPURR(r13); \
> subf rb,rb,ra; /* subtract start value */ \
> @@ -274,6 +274,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
> #define ISYNC_601
> #endif
>
> +#ifdef CONFIG_PPC_CELL
> +#define MFTB(dest) \
> + mftb dest; \
> +BEGIN_FTR_SECTION; \
> + cmpwi dest,0; \
> + bne+ 90f; \
> + mftb dest; \
> +90: \
> +END_FTR_SECTION_IFSET(CPU_FTR_CELL_TB_BUG)
> +#else
> +#define MFTB(dest) mftb dest
> +#endif
The above is a bit obfuscated. Please make the MFTB() macro use the
nested version of the feature definitions, and let the surrounding code
use the base one. Otherwise it will be really easy to mix them up by
mistake, there's no exposure at the time of MFTB() usage that it uses
feature labels.
-Olof
^ permalink raw reply
* Re: [PATCH 1/4] powerpc: consolidate feature fixup code
From: Olof Johansson @ 2006-10-12 13:56 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1160641793.4792.133.camel@localhost.localdomain>
On Thu, 12 Oct 2006 18:29:53 +1000 Benjamin Herrenschmidt <benh@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@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@h /* nop */
> -3: stw r0,0(r8)
> - andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@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@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@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* Re: plb_temac, ML403, linux 2.4.26, EDK 7.1
From: Andrei Konovalov @ 2006-10-12 12:46 UTC (permalink / raw)
To: robert corley; +Cc: linuxppc-embedded
In-Reply-To: <20061011204632.80180.qmail@web56309.mail.re3.yahoo.com>
Robert,
There is no support for TEMAC in MontaVista Linux 3.1. It has been added in MVL 4.0.1.
In 3.1 there is the gige driver, but gige is for ML300's optical gigabit ethernet, not for TEMAC.
Thanks,
Andrei
robert corley wrote:
> Ming;
>
> Here is what the EDK generates in this file:
>
> C:\EDK\projects\startup_network\ppc405_0\libsrc\linux_mvl31_v1_01_a\linux\arch\ppc\platforms\xilinx_ocp\xparameters_ml300.h
>
> <snip>
> #define XPAR_XTEMAC_NUM_INSTANCES 1
> #define XPAR_PLB_TEMAC_0_BASEADDR 0x60000000
> #define XPAR_PLB_TEMAC_0_HIGHADDR 0x60003FFF
> #define XPAR_PLB_TEMAC_0_DEVICE_ID 0
> #define XPAR_PLB_TEMAC_0_IPIF_RDFIFO_DEPTH 131072
> #define XPAR_PLB_TEMAC_0_IPIF_WRFIFO_DEPTH 131072
> #define XPAR_PLB_TEMAC_0_MAC_FIFO_DEPTH 64
> #define XPAR_PLB_TEMAC_0_DMA_TYPE 3
> #define XPAR_PLB_TEMAC_0_TEMAC_DCR_HOST 0
> #define XPAR_PLB_TEMAC_0_INCLUDE_DRE 1
> <snip>
>
>
> Which is fine. However, the file in the linux distribution: linux_2_4_devel/drivers/net/xilinx_enet/adapter.c is looking for "XEMAC" instead of "XTEMAC" as above.
>
> Also, when I look at the EDK project directory
>
> "C:\EDK\projects\startup_network\ppc405_0\libsrc\linux_mvl31_v1_01_a\linux\drivers\net\"
>
> I see that it is empty. Which means that nothing in the MVL tree will be overwritten (specifically the adapter.c file, which uses the above defines).
>
> So, it appears that the driver is not being properly insterted into the tree as expected. Would you agree?
>
> -R
>
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* [PATCH 2/2] Add support for dumping spu info from xmon
From: Michael Ellerman @ 2006-10-12 12:03 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, cbe-oss-dev
In-Reply-To: <1160654587.449977.520618728447.qpush@concordia>
This patch adds a command to xmon for dumping information about
spu structs. The command is 'sf' for "spu fields" perhaps, and
takes the spu number as an argument. This is the same value as the
spu->number field, or the "phys-id" value of a context when it is
bound to a physical spu.
We try to catch memory errors as we dump each field, hopefully this
will make the command reasonably robust, but YMMV. If people see a
need we can easily add more fields to the dump in future.
Output looks something like this:
0:mon> sf 0
Dumping spu fields at address c00000001ffd9e80:
number = 0x0
name = spe
devnode->full_name = /cpus/PowerPC,BE@0/spes/spe@0
nid = 0x0
local_store_phys = 0x20000000000
local_store = 0xd0000800801e0000
ls_size = 0x0
isrc = 0x4
node = 0x0
flags = 0x0
dar = 0x0
dsisr = 0x0
class_0_pending = 0
irqs[0] = 0x16
irqs[1] = 0x17
irqs[2] = 0x24
slb_replace = 0x0
pid = 0
prio = 0
mm = 0x0000000000000000
ctx = 0x0000000000000000
rq = 0x0000000000000000
timestamp = 0x0000000000000000
problem_phys = 0x20000040000
problem = 0xd000080080220000
problem->spu_runcntl_RW = 0x0
problem->spu_status_R = 0x0
problem->spu_npc_RW = 0x0
priv1 = 0xd000080080240000
priv1->mfc_sr1_RW = 0x33
priv2 = 0xd000080080250000
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/xmon/xmon.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)
Index: to-merge/arch/powerpc/xmon/xmon.c
===================================================================
--- to-merge.orig/arch/powerpc/xmon/xmon.c
+++ to-merge/arch/powerpc/xmon/xmon.c
@@ -214,7 +214,8 @@ Commands:\n\
s single step\n"
#ifdef CONFIG_PPC_CELL
" ss stop execution on all spus\n\
- sr restore execution on stopped spus\n"
+ sr restore execution on stopped spus\n\
+ sf # dump spu fields for spu # (in hex)\n"
#endif
" S print special registers\n\
t print backtrace\n\
@@ -2744,8 +2745,67 @@ static void restart_spus(void)
}
}
+#define DUMP_WIDTH 23
+#define DUMP_FIELD(obj, format, field) \
+do { \
+ if (setjmp(bus_error_jmp) == 0) { \
+ catch_memory_errors = 1; \
+ sync(); \
+ printf(" %-*s = "format"\n", DUMP_WIDTH, \
+ #field, obj->field); \
+ sync(); \
+ __delay(200); \
+ } else { \
+ catch_memory_errors = 0; \
+ printf(" %-*s = *** Error reading field.\n", \
+ DUMP_WIDTH, #field); \
+ } \
+ catch_memory_errors = 0; \
+} while (0)
+
+static void dump_spu_fields(struct spu *spu)
+{
+ printf("Dumping spu fields at address %p:\n", spu);
+
+ DUMP_FIELD(spu, "0x%x", number);
+ DUMP_FIELD(spu, "%s", name);
+ DUMP_FIELD(spu, "%s", devnode->full_name);
+ DUMP_FIELD(spu, "0x%x", nid);
+ DUMP_FIELD(spu, "0x%lx", local_store_phys);
+ DUMP_FIELD(spu, "0x%p", local_store);
+ DUMP_FIELD(spu, "0x%lx", ls_size);
+ DUMP_FIELD(spu, "0x%x", isrc);
+ DUMP_FIELD(spu, "0x%x", node);
+ DUMP_FIELD(spu, "0x%lx", flags);
+ DUMP_FIELD(spu, "0x%lx", dar);
+ DUMP_FIELD(spu, "0x%lx", dsisr);
+ DUMP_FIELD(spu, "%d", class_0_pending);
+ DUMP_FIELD(spu, "0x%lx", irqs[0]);
+ DUMP_FIELD(spu, "0x%lx", irqs[1]);
+ DUMP_FIELD(spu, "0x%lx", irqs[2]);
+ DUMP_FIELD(spu, "0x%x", slb_replace);
+ DUMP_FIELD(spu, "%d", pid);
+ DUMP_FIELD(spu, "%d", prio);
+ DUMP_FIELD(spu, "0x%p", mm);
+ DUMP_FIELD(spu, "0x%p", ctx);
+ DUMP_FIELD(spu, "0x%p", rq);
+ DUMP_FIELD(spu, "0x%p", timestamp);
+ DUMP_FIELD(spu, "0x%lx", problem_phys);
+ DUMP_FIELD(spu, "0x%p", problem);
+ DUMP_FIELD(spu, "0x%x", problem->spu_runcntl_RW);
+ DUMP_FIELD(spu, "0x%x", problem->spu_status_R);
+ DUMP_FIELD(spu, "0x%x", problem->spu_npc_RW);
+ DUMP_FIELD(spu, "0x%p", priv1);
+
+ if (spu->priv1)
+ DUMP_FIELD(spu, "0x%lx", priv1->mfc_sr1_RW);
+
+ DUMP_FIELD(spu, "0x%p", priv2);
+}
+
static int do_spu_cmd(void)
{
+ unsigned long num = 0;
int cmd;
cmd = inchar();
@@ -2756,6 +2816,12 @@ static int do_spu_cmd(void)
case 'r':
restart_spus();
break;
+ case 'f':
+ if (scanhex(&num) && num < XMON_NUM_SPUS && spu_info[num].spu)
+ dump_spu_fields(spu_info[num].spu);
+ else
+ printf("*** Error: invalid spu number\n");
+ break;
default:
return -1;
}
^ permalink raw reply
* [PATCH 1/2] Add support for stopping spus from xmon
From: Michael Ellerman @ 2006-10-12 12:03 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, cbe-oss-dev
In-Reply-To: <1160654587.449977.520618728447.qpush@concordia>
This patch adds support for stopping, and restarting, spus
from xmon. We use the spu master runcntl bit to stop execution,
this is apparently the "right" way to control spu execution and
spufs will be changed in the future to use this bit.
Testing has shown that to restart execution we have to turn the
master runcntl bit on and also rewrite the spu runcntl bit, even
if it is already set to 1 (running).
Stopping spus is triggered by the xmon command 'ss' - "spus stop"
perhaps. Restarting them is triggered via 'sr'. Restart doesn't
start execution on spus unless they were running prior to being
stopped by xmon.
Walking the spu->full_list in xmon after a panic, would mean
corruption of any spu struct would make all the others
inaccessible. To avoid this, and also to make the next patch
easier, we cache pointers to all spus during boot.
We attempt to catch and recover from errors while stopping and
restarting the spus, but as with most xmon functionality there are
no guarantees that performing these operations won't crash xmon
itself.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/cell/spu_base.c | 4
arch/powerpc/xmon/xmon.c | 142 ++++++++++++++++++++++++++++++++-
include/asm-powerpc/xmon.h | 2
3 files changed, 146 insertions(+), 2 deletions(-)
Index: to-merge/arch/powerpc/platforms/cell/spu_base.c
===================================================================
--- to-merge.orig/arch/powerpc/platforms/cell/spu_base.c
+++ to-merge/arch/powerpc/platforms/cell/spu_base.c
@@ -38,6 +38,7 @@
#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/mmu_context.h>
+#include <asm/xmon.h>
#include "interrupt.h"
@@ -914,6 +915,9 @@ static int __init init_spu_base(void)
break;
}
}
+
+ xmon_register_spus(&spu_full_list);
+
return ret;
}
module_init(init_spu_base);
Index: to-merge/arch/powerpc/xmon/xmon.c
===================================================================
--- to-merge.orig/arch/powerpc/xmon/xmon.c
+++ to-merge/arch/powerpc/xmon/xmon.c
@@ -35,6 +35,8 @@
#include <asm/rtas.h>
#include <asm/sstep.h>
#include <asm/bug.h>
+#include <asm/spu.h>
+#include <asm/spu_priv1.h>
#ifdef CONFIG_PPC64
#include <asm/hvcall.h>
@@ -145,6 +147,8 @@ static void xmon_print_symbol(unsigned l
const char *after);
static const char *getvecname(unsigned long vec);
+static int do_spu_cmd(void);
+
int xmon_no_auto_backtrace;
extern int print_insn_powerpc(unsigned long, unsigned long, int);
@@ -207,8 +211,12 @@ Commands:\n\
mi show information about memory allocation\n\
p call a procedure\n\
r print registers\n\
- s single step\n\
- S print special registers\n\
+ s single step\n"
+#ifdef CONFIG_PPC_CELL
+" ss stop execution on all spus\n\
+ sr restore execution on stopped spus\n"
+#endif
+" S print special registers\n\
t print backtrace\n\
x exit monitor and recover\n\
X exit monitor and dont recover\n"
@@ -516,6 +524,7 @@ int xmon(struct pt_regs *excp)
xmon_save_regs(®s);
excp = ®s;
}
+
return xmon_core(excp, 0);
}
EXPORT_SYMBOL(xmon);
@@ -808,6 +817,8 @@ cmds(struct pt_regs *excp)
cacheflush();
break;
case 's':
+ if (do_spu_cmd() == 0)
+ break;
if (do_step(excp))
return cmd;
break;
@@ -2630,3 +2641,130 @@ void __init xmon_setup(void)
if (xmon_early)
debugger(NULL);
}
+
+#ifdef CONFIG_PPC_CELL
+
+struct spu_info {
+ struct spu *spu;
+ u64 saved_mfc_sr1_RW;
+ u32 saved_spu_runcntl_RW;
+ u8 stopped_ok;
+};
+
+#define XMON_NUM_SPUS 16 /* Enough for current hardware */
+
+static struct spu_info spu_info[XMON_NUM_SPUS];
+
+void xmon_register_spus(struct list_head *list)
+{
+ struct spu *spu;
+
+ list_for_each_entry(spu, list, full_list) {
+ if (spu->number >= XMON_NUM_SPUS) {
+ WARN_ON(1);
+ continue;
+ }
+
+ spu_info[spu->number].spu = spu;
+ spu_info[spu->number].stopped_ok = 0;
+ }
+}
+
+static void stop_spus(void)
+{
+ struct spu *spu;
+ int i;
+ u64 tmp;
+
+ for (i = 0; i < XMON_NUM_SPUS; i++) {
+ if (!spu_info[i].spu)
+ continue;
+
+ if (setjmp(bus_error_jmp) == 0) {
+ catch_memory_errors = 1;
+ sync();
+
+ spu = spu_info[i].spu;
+
+ spu_info[i].saved_spu_runcntl_RW =
+ in_be32(&spu->problem->spu_runcntl_RW);
+
+ tmp = spu_mfc_sr1_get(spu);
+ spu_info[i].saved_mfc_sr1_RW = tmp;
+
+ tmp &= ~MFC_STATE1_MASTER_RUN_CONTROL_MASK;
+ spu_mfc_sr1_set(spu, tmp);
+
+ sync();
+ __delay(200);
+
+ spu_info[i].stopped_ok = 1;
+ printf("Stopped spu %.2d\n", i);
+ } else {
+ catch_memory_errors = 0;
+ printf("*** Error stopping spu %.2d\n", i);
+ }
+ catch_memory_errors = 0;
+ }
+}
+
+static void restart_spus(void)
+{
+ struct spu *spu;
+ int i;
+
+ for (i = 0; i < XMON_NUM_SPUS; i++) {
+ if (!spu_info[i].spu)
+ continue;
+
+ if (!spu_info[i].stopped_ok) {
+ printf("*** Error, spu %d was not successfully stopped"
+ ", not restarting\n", i);
+ continue;
+ }
+
+ if (setjmp(bus_error_jmp) == 0) {
+ catch_memory_errors = 1;
+ sync();
+
+ spu = spu_info[i].spu;
+ spu_mfc_sr1_set(spu, spu_info[i].saved_mfc_sr1_RW);
+ out_be32(&spu->problem->spu_runcntl_RW,
+ spu_info[i].saved_spu_runcntl_RW);
+
+ sync();
+ __delay(200);
+
+ printf("Restarted spu %.2d\n", i);
+ } else {
+ catch_memory_errors = 0;
+ printf("*** Error restarting spu %.2d\n", i);
+ }
+ catch_memory_errors = 0;
+ }
+}
+
+static int do_spu_cmd(void)
+{
+ int cmd;
+
+ cmd = inchar();
+ switch (cmd) {
+ case 's':
+ stop_spus();
+ break;
+ case 'r':
+ restart_spus();
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+#else /* ! CONFIG_PPC_CELL */
+static int do_spu_cmd(void)
+{
+ return -1;
+}
+#endif
Index: to-merge/include/asm-powerpc/xmon.h
===================================================================
--- to-merge.orig/include/asm-powerpc/xmon.h
+++ to-merge/include/asm-powerpc/xmon.h
@@ -14,8 +14,10 @@
#ifdef CONFIG_XMON
extern void xmon_setup(void);
+extern void xmon_register_spus(struct list_head *list);
#else
static inline void xmon_setup(void) { };
+static inline void xmon_register_spus(struct list_head *list) { };
#endif
#endif /* __KERNEL __ */
^ permalink raw reply
* [PATCH 0/2] Cell xmon helpers
From: Michael Ellerman @ 2006-10-12 12:03 UTC (permalink / raw)
To: Arnd Bergmann; +Cc: linuxppc-dev, cbe-oss-dev
The following two patches add three commands to xmon for stopping,
restarting and dumping info about spus from xmon.
For the folks on linuxppc-dev, these patches depend on another patch
which isn't in the powerpc tree yet AFAIK, you can get it here:
http://kernel.org/pub/linux/kernel/people/arnd/patches/2.6.17-arnd8/broken-out/spu-add-attributes.diff
cheers
^ permalink raw reply
* PPChameleonEVB Newbie question
From: Adrian @ 2006-10-12 11:47 UTC (permalink / raw)
To: linuxppc-embedded
Thanks Wolfgang.
I have now got the target compiling modules, kernel and everything.
For the record, I found it very difficult and time consuming.
To get to this stage I had to :-
Install Slack 8.1 kernel 2.4.18
Install ELDK version 4
as per docs add /usr/local/eldk/usr/bin:/usr/local/eldk/bin to PATH
set and export ARCH=ppc, CROSS_COMPILE=ppc_4xx-
make mrproper
make PPChameleon_defconfig
edit arch/ppc/platforms/4xx/Kconfig and add
'select WANT_EARLY_SERIAL'
to PPChameleonEVB definition
make menuconfig
make
then copy kernel to /tftpboot dir.
Board then booted ok provided the ELDK instructions about NFS shares were
followed.
Under Slack 9 + 10.1 the kernel cross-compile barfed with 'clobber list'
errors.
The dev host would cross-compile the modules, but wouldn't install them
(INSTALL_MOD_PATH set).
After that i wanted to build the Kernel and modules on the target to make
sure it was all ok, so :-
Installed Perl 5.6.4 with etc/Digest/MD5 copied from Perl 5.8.2 tree
(make modules_install wouldn't work without perl, and it isn't supplied
AFAICS)
cd /usr/src/linux/include
ln -s asm-ppc asm
make mrproper
make PPChameleon_defconfig
edit arch/ppc/platforms/4xx/Kconfig and add
'select WANT_EARLY_SERIAL'
to PPChameleonEVB definition
make menuconfig
make
make modules
make modules_install
On the target it is (naturally) slow and you have to set up some NFS shared
swap if you don't have much ram (i have 32mb and the kernel compile ran out
of memory).
Out of the box i couldn't get ELDK 3.1.1 working at all, and the
linux-2.4.20-pelk- thing wouldn't compile under either.
The main hurdle was needing to retro-grade the dev host.
Anyway. It is working happily now. Thanks for your help.
Adrian Atkins
IT Live Limited
tel: 0161 408 3327
fax: 08702 360 443
skype: adrianitlive
ES mob: (0034) 606806236
^ permalink raw reply
* Re: [PATCH 1/4] powerpc: consolidate feature fixup code
From: Benjamin Herrenschmidt @ 2006-10-12 10:48 UTC (permalink / raw)
To: michael; +Cc: linuxppc-dev list
In-Reply-To: <1160646965.16101.4.camel@localhost.localdomain>
> > 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;
>
>
> Every extern in a C file ... god kills a kitten! :)
Well... it's a bit special in this case.. just a reference to a section,
I'd rather keep it close to the only call site...
Ben.
^ permalink raw reply
* Re: [PATCH] Xilinx UART Lite 2.6.18 driver
From: Peter Korsgaard @ 2006-10-12 10:34 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <609d5c8e0610101349w64cdd4ecjc5359ad8d1f5d635@mail.gmail.com>
>>>>> "David" == David Bolcsfoldi <dbolcsfoldi@gmail.com> writes:
Hi David,
David> here's a set of patches that adds support for Xilinx UART lite
David> devices. It has been tested on an ML403-FX using xapp902
David> (ml403_ppc_plb_temac) using a 2.6.18 kernel and a BusyBox
David> userspace.
I guess you didn't know, but there already exists a uartlite driver!
It unfortunately didn't made it into 2.6.19-rc1 because Russell
stopped maintaining serial stuff, but it's in -mm.
It also has an official lanana.org assigned set of device nodes.
I didn't look at your patch yet, but I think it would be more useful
to add any features missing to my driver than writing yet another
driver (I think we're up to 3 now).
--
Bye, Peter Korsgaard
^ permalink raw reply
* Re: Handling machine check exception
From: Matt Sealey @ 2006-10-12 10:34 UTC (permalink / raw)
To: ganesh subramonian; +Cc: linuxppc-dev
In-Reply-To: <20061012045943.9389.qmail@web52403.mail.yahoo.com>
The G2 core definitely has a DAR register (SPR 19).
Look on the Freescale site for G2CORERM.pdf - this is
your reference manual, not the one specifically for the
8247.
--
Matt Sealey <matt@genesi-usa.com>
Genesi, Manager, Developer Relations
ganesh subramonian wrote:
> Hi,
>
> I am trying to modify the machinecheck exception
> handler so that checks caused by data access to a
> particular address range can be ignored. In mpc866
> there is a register called DAR(Data Address Register)
> which gives the address[access to] which caused the
> exception. However this is not mentioned in the
> MPC8247 manual. Is there some equivalent register for
> 8247. (It seemed to me that the DAR should be a core
> register and hence should be there on 8247 also. but
> if i try to read i really dont get the address causing
> the error).
>
> Or is there some way i can specify that access to a
> particular range of address should not cause a machine
> check?? Please help.
>
> thanks
> ganesh
>
> __________________________________________________
> Do You Yahoo!?
> Tired of spam? Yahoo! Mail has the best spam protection around
> http://mail.yahoo.com
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
^ permalink raw reply
* SystemACE in a multiprocessor system
From: Alireza Sadri @ 2006-10-12 10:13 UTC (permalink / raw)
To: linuxppc-embedded
Hi,
My question is about using only one SystemACE in a
board containing several Virtex4 chips all in the JTAG
chain.
How are kernels run on these processors, as only one
of these FPGAs are connected to this CompactFlash
directly.
Regards,
Ali R. Sadri,
Sarv-net Inc.
www.sarv-net.com
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
^ permalink raw reply
* unsubscribe
From: Usha Rani Konudula @ 2006-10-12 9:56 UTC (permalink / raw)
To: linuxppc-dev list
unsubscribe
^ permalink raw reply
* Re: [PATCH 1/4] powerpc: consolidate feature fixup code
From: Michael Ellerman @ 2006-10-12 9:56 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1160641793.4792.133.camel@localhost.localdomain>
[-- Attachment #1: Type: text/plain, Size: 2740 bytes --]
On Thu, 2006-10-12 at 18:29 +1000, Benjamin Herrenschmidt 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).
Nice to see it written in C :)
> 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;
> 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;
Every extern in a C file ... god kills a kitten! :)
cheers
--
Michael Ellerman
OzLabs, IBM Australia Development Lab
wwweb: http://michael.ellerman.id.au
phone: +61 2 6212 1183 (tie line 70 21183)
We do not inherit the earth from our ancestors,
we borrow it from our children. - S.M.A.R.T Person
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 191 bytes --]
^ permalink raw reply
* [PATCH 4/4] powerpc: Cell timebase workaround
From: Benjamin Herrenschmidt @ 2006-10-12 8:30 UTC (permalink / raw)
To: linuxppc-dev list
The Cell CPU timebase has an errata. When reading the entire 64 bits of
the timebase with one mftb instruction, there is a handful of cycles
window during which one might read a value with the low order 32 bits
already reset to 0x00000000 but the high order bits not yet incremeted
by one. Simply reading the timebase a second time if the low order bits
are 0 is enough (the second read will always miss that window).
Note that there is still a potential issue if the process gets
interrupted between the 2 reads for long enough that the second reads
pricely hits that same window on the next 32 bits wrap. However, this is
so extremely unlikely to happen that we choose not to do anything
against it (the 32 bits wrap happens every few seconds or so, in fact
every few minutes on IBM cell blades).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
This is the "old" patch adapted to apply on top of the previous changes.
I'll post tomorrow a new version of the patch using a different
technique for the workaround
Index: linux-cell/arch/powerpc/kernel/vdso64/gettimeofday.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vdso64/gettimeofday.S 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vdso64/gettimeofday.S 2006-10-12 18:18:15.000000000 +1000
@@ -11,6 +11,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/vdso.h>
@@ -229,8 +230,13 @@ V_FUNCTION_BEGIN(__do_get_xsec)
xor r0,r8,r8 /* create dependency */
add r3,r3,r0
- /* Get TB & offset it */
- mftb r7
+ /* Get TB & offset it. We use the MFTB macro which will generate
+ * workaround code for Cell. The macro will generate the ELF bits
+ * for the CPU feature fixup though those aren't actually applied
+ * on the vDSO, which means that the workaround will always be
+ * executed if CONFIG_PPC_CELL is set.
+ */
+ MFTB(r7)
ld r9,CFG_TB_ORIG_STAMP(r3)
subf r7,r9,r7
Index: linux-cell/include/asm-powerpc/cputable.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/cputable.h 2006-10-12 18:17:44.000000000 +1000
+++ linux-cell/include/asm-powerpc/cputable.h 2006-10-12 18:18:15.000000000 +1000
@@ -144,6 +144,7 @@ extern void do_cpu_ftr_fixups(unsigned l
#define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000)
#define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000)
#define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000)
+#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000)
#ifndef __ASSEMBLY__
@@ -332,7 +333,7 @@ extern void do_cpu_ftr_fixups(unsigned l
#define CPU_FTRS_CELL (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
- CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE)
+ CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
#define CPU_FTRS_PA6T (CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
Index: linux-cell/include/asm-powerpc/ppc_asm.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/ppc_asm.h 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/include/asm-powerpc/ppc_asm.h 2006-10-12 18:18:15.000000000 +1000
@@ -29,10 +29,10 @@
BEGIN_FTR_SECTION; \
mfspr ra,SPRN_PURR; /* get processor util. reg */ \
END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
-BEGIN_FTR_SECTION; \
- mftb ra; /* or get TB if no PURR */ \
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
- ld rb,PACA_STARTPURR(r13); \
+BEGIN_FTR_SECTION_NESTED(96); \
+ MFTB(ra); /* or get TB if no PURR */ \
+END_FTR_SECTION_NESTED(CPU_FTR_PURR, 0, 96); \
+ ld rb,PACA_STARTPURR(r13); \
std ra,PACA_STARTPURR(r13); \
subf rb,rb,ra; /* subtract start value */ \
ld ra,PACA_USER_TIME(r13); \
@@ -44,9 +44,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_PURR);
BEGIN_FTR_SECTION; \
mfspr ra,SPRN_PURR; /* get processor util. reg */ \
END_FTR_SECTION_IFSET(CPU_FTR_PURR); \
-BEGIN_FTR_SECTION; \
- mftb ra; /* or get TB if no PURR */ \
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR); \
+BEGIN_FTR_SECTION_NESTED(96); \
+ MFTB(ra); /* or get TB if no PURR */ \
+END_FTR_SECTION_NESTED(CPU_FTR_PURR, 0, 96); \
ld rb,PACA_STARTPURR(r13); \
std ra,PACA_STARTPURR(r13); \
subf rb,rb,ra; /* subtract start value */ \
@@ -274,6 +274,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
#define ISYNC_601
#endif
+#ifdef CONFIG_PPC_CELL
+#define MFTB(dest) \
+ mftb dest; \
+BEGIN_FTR_SECTION; \
+ cmpwi dest,0; \
+ bne+ 90f; \
+ mftb dest; \
+90: \
+END_FTR_SECTION_IFSET(CPU_FTR_CELL_TB_BUG)
+#else
+#define MFTB(dest) mftb dest
+#endif
#ifndef CONFIG_SMP
#define TLBSYNC
Index: linux-cell/include/asm-powerpc/reg.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/reg.h 2006-10-12 18:17:44.000000000 +1000
+++ linux-cell/include/asm-powerpc/reg.h 2006-10-12 18:19:05.000000000 +1000
@@ -617,9 +617,28 @@
asm volatile("mfspr %0," __stringify(rn) \
: "=r" (rval)); rval;})
#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : : "r" (v))
-
+#ifdef CONFIG_PPC_CELL
+#define mftb() ({unsigned long rval; \
+ asm volatile( \
+ " mftb %0;\n" \
+ "97: cmpwi %0,0;\n" \
+ " bne+ 99f;\n" \
+ " mftb %0;\n" \
+ "99:\n" \
+ ".section __ftr_fixup,\"a\"\n" \
+ ".align 3\n" \
+ "98:\n" \
+ " .llong %1\n" \
+ " .llong %1\n" \
+ " .llong 97b-98b\n" \
+ " .llong 99b-98b\n" \
+ ".previous" \
+ : "=r" (rval) : "i" (CPU_FTR_CELL_TB_BUG)); rval;})
+#else
#define mftb() ({unsigned long rval; \
asm volatile("mftb %0" : "=r" (rval)); rval;})
+#endif
+
#define mftbl() ({unsigned long rval; \
asm volatile("mftbl %0" : "=r" (rval)); rval;})
Index: linux-cell/include/asm-powerpc/time.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/time.h 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/include/asm-powerpc/time.h 2006-10-12 18:18:15.000000000 +1000
@@ -85,26 +85,28 @@ struct div_result {
/* On ppc64 this gets us the whole timebase; on ppc32 just the lower half */
static inline unsigned long get_tbl(void)
{
- unsigned long tbl;
-
#if defined(CONFIG_403GCX)
+ unsigned long tbl;
asm volatile("mfspr %0, 0x3dd" : "=r" (tbl));
+ return tbl;
+#elif defined(CONFIG_PPC32)
+ return mftbl();
#else
- asm volatile("mftb %0" : "=r" (tbl));
+ return mftb();
#endif
- return tbl;
}
static inline unsigned int get_tbu(void)
{
+#ifdef CONFIG_403GCX
unsigned int tbu;
-
-#if defined(CONFIG_403GCX)
asm volatile("mfspr %0, 0x3dc" : "=r" (tbu));
+ return tbu;
+#elif defined(CONFIG_PPC32)
+ return mftbu();
#else
- asm volatile("mftbu %0" : "=r" (tbu));
+ return mftb();
#endif
- return tbu;
}
static inline unsigned int get_rtcl(void)
Index: linux-cell/include/asm-powerpc/timex.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/timex.h 2006-10-12 18:17:44.000000000 +1000
+++ linux-cell/include/asm-powerpc/timex.h 2006-10-12 18:18:15.000000000 +1000
@@ -8,6 +8,7 @@
*/
#include <asm/cputable.h>
+#include <asm/reg.h>
#define CLOCK_TICK_RATE 1024000 /* Underlying HZ */
@@ -15,13 +16,11 @@ typedef unsigned long cycles_t;
static inline cycles_t get_cycles(void)
{
- cycles_t ret;
-
#ifdef __powerpc64__
-
- __asm__ __volatile__("mftb %0" : "=r" (ret) : );
-
+ return mftb();
#else
+ cycles_t ret;
+
/*
* For the "cycle" counter we use the timebase lower half.
* Currently only used on SMP.
@@ -41,9 +40,8 @@ static inline cycles_t get_cycles(void)
" .long 99b-98b\n"
".previous"
: "=r" (ret) : "i" (CPU_FTR_601));
-#endif
-
return ret;
+#endif
}
#endif /* __KERNEL__ */
^ permalink raw reply
* [PATCH 3/4] powerpc: Support feature fixups in vdso's
From: Benjamin Herrenschmidt @ 2006-10-12 8:30 UTC (permalink / raw)
To: linuxppc-dev list
This patch is the "meat" of the series. It reworks the feature fixup
mecanism so vdso's can be fixed up. The main issue was that the
construct:
.long label (or .llong on 64 bits)
will not work in the case of a shared library like the vdso. It will
generate an empty placeholder in the fixup table along with a reloc,
which is not something we can deal with in the vdso.
The idea here (thanks Alan Modra !) is to instead use something like:
1:
.long label - 1b
That is, the feature fixup tables no longer contain addresses of bits of
code to patch, but offsets of such code from the fixup table entry
itself. That is properly resolved by ld when building the .so's. I've
modified the fixup mecanism generically to use that method for the rest
of the kernel as well.
Another trick is that the 32 bits vDSO included in the 64 bits kernel
need to have a table in the 64 bits format. However, gas does not
support 32 bits code with a statement of the form:
.llong label - 1b (Or even just .llong label)
That is, it cannot emit the right fixup/relocation for the linker to use
to assign a 32 bits address to an .llong field. Thus, in the specific
case of the 32 bits vdso built as part of the 64 bits kernel, we are
using a modified macro that generates:
.long 0xffffffff
.llong label - 1b
Note that is assumes that the value is negative which is enforced by
the .lds (those offsets are always negative as the .text is always
before the fixup table and gas doesn't support emiting the reloc the
other way around).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-cell/arch/powerpc/kernel/vdso.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vdso.c 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vdso.c 2006-10-12 18:17:44.000000000 +1000
@@ -36,6 +36,8 @@
#include <asm/vdso.h>
#include <asm/vdso_datapage.h>
+#include "setup.h"
+
#undef DEBUG
#ifdef DEBUG
@@ -586,6 +588,43 @@ static __init int vdso_fixup_datapage(st
return 0;
}
+
+static __init int vdso_fixup_features(struct lib32_elfinfo *v32,
+ struct lib64_elfinfo *v64)
+{
+ void *start32;
+ unsigned long size32, offset32;
+
+#ifdef CONFIG_PPC64
+ void *start64;
+ unsigned long size64, offset64;
+
+ start64 = find_section64(v64->hdr, "__ftr_fixup", &size64);
+ if (start64)
+ do_feature_fixups(cur_cpu_spec->cpu_features,
+ start64, start64 + size64);
+
+ start64 = find_section64(v64->hdr, "__fw_ftr_fixup", &size64);
+ if (start64)
+ do_feature_fixups(powerpc_firmware_features,
+ start64, start64 + size64);
+#endif /* CONFIG_PPC64 */
+
+ start32 = find_section32(v32->hdr, "__ftr_fixup", &size32);
+ if (start32)
+ do_feature_fixups(cur_cpu_spec->cpu_features,
+ start32, start32 + size32);
+
+#ifdef CONFIG_PPC64
+ start32 = find_section32(v32->hdr, "__fw_ftr_fixup", &size32);
+ if (start32)
+ do_feature_fixups(powerpc_firmware_features,
+ start32, start32 + size32);
+#endif /* CONFIG_PPC64 */
+
+ return 0;
+}
+
static __init int vdso_fixup_alt_funcs(struct lib32_elfinfo *v32,
struct lib64_elfinfo *v64)
{
@@ -634,6 +673,9 @@ static __init int vdso_setup(void)
if (vdso_fixup_datapage(&v32, &v64))
return -1;
+ if (vdso_fixup_features(&v32, &v64))
+ return -1;
+
if (vdso_fixup_alt_funcs(&v32, &v64))
return -1;
@@ -714,6 +756,7 @@ void __init vdso_init(void)
* Setup the syscall map in the vDOS
*/
vdso_setup_syscall_map();
+
/*
* Initialize the vDSO images in memory, that is do necessary
* fixups of vDSO symbols, locate trampolines, etc...
Index: linux-cell/arch/powerpc/kernel/vdso32/vdso32.lds.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vdso32/vdso32.lds.S 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vdso32/vdso32.lds.S 2006-10-12 18:17:44.000000000 +1000
@@ -32,6 +32,18 @@ SECTIONS
PROVIDE (_etext = .);
PROVIDE (etext = .);
+ . = ALIGN(8);
+ __ftr_fixup : {
+ *(__ftr_fixup)
+ }
+
+#ifdef CONFIG_PPC64
+ . = ALIGN(8);
+ __fw_ftr_fixup : {
+ *(__fw_ftr_fixup)
+ }
+#endif
+
/* Other stuff is appended to the text segment: */
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
Index: linux-cell/arch/powerpc/kernel/vdso64/vdso64.lds.S
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/vdso64/vdso64.lds.S 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/vdso64/vdso64.lds.S 2006-10-12 18:17:44.000000000 +1000
@@ -31,6 +31,16 @@ SECTIONS
PROVIDE (_etext = .);
PROVIDE (etext = .);
+ . = ALIGN(8);
+ __ftr_fixup : {
+ *(__ftr_fixup)
+ }
+
+ . = ALIGN(8);
+ __fw_ftr_fixup : {
+ *(__fw_ftr_fixup)
+ }
+
/* Other stuff is appended to the text segment: */
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
Index: linux-cell/arch/powerpc/kernel/setup-common.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup-common.c 2006-10-12 18:17:37.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup-common.c 2006-10-12 18:17:44.000000000 +1000
@@ -521,27 +521,29 @@ 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)
+void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
{
struct fixup_entry {
unsigned long mask;
unsigned long value;
- unsigned int *start;
- unsigned int *end;
+ long start_off;
+ long end_off;
} *fcur, *fend;
fcur = fixup_start;
fend = fixup_end;
+ printk("fixup using section %p -> %p, value: 0x%lx\n",
+ fixup_start, fixup_end, value);
+
for (; fcur < fend; fcur++) {
unsigned int *pcur, *pend;
if ((value & fcur->mask) == fcur->value)
continue;
- pcur = fcur->start - offset;
- pend = fcur->end - offset;
+ pcur = ((unsigned int *)fcur) + (fcur->start_off / 4);
+ pend = ((unsigned int *)fcur) + (fcur->end_off / 4);
for (; pcur < pend; pcur++) {
*pcur = 0x60000000u;
asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync"
Index: linux-cell/arch/powerpc/kernel/setup.h
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup.h 2006-10-12 18:17:37.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup.h 2006-10-12 18:17:44.000000000 +1000
@@ -4,8 +4,8 @@
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 void do_feature_fixups(unsigned long value, void *fixup_start,
+ void *fixup_end);
extern int do_early_xmon;
Index: linux-cell/arch/powerpc/kernel/setup_32.c
===================================================================
--- linux-cell.orig/arch/powerpc/kernel/setup_32.c 2006-10-12 18:17:37.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup_32.c 2006-10-12 18:17:44.000000000 +1000
@@ -103,7 +103,7 @@ unsigned long __init early_init(unsigned
*/
identify_cpu(offset, 0);
- do_feature_fixups(offset, cur_cpu_spec->cpu_features,
+ do_feature_fixups(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 18:17:37.000000000 +1000
+++ linux-cell/arch/powerpc/kernel/setup_64.c 2006-10-12 18:17:44.000000000 +1000
@@ -354,9 +354,9 @@ void __init setup_system(void)
/* 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,
+ do_feature_fixups(cur_cpu_spec->cpu_features,
&__start___ftr_fixup, &__stop___ftr_fixup);
- do_feature_fixups(0, powerpc_firmware_features,
+ do_feature_fixups(powerpc_firmware_features,
&__start___fw_ftr_fixup, &__stop___fw_ftr_fixup);
/*
Index: linux-cell/include/asm-powerpc/asm-compat.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/asm-compat.h 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/include/asm-powerpc/asm-compat.h 2006-10-12 18:17:44.000000000 +1000
@@ -14,6 +14,58 @@
# define ASM_CONST(x) __ASM_CONST(x)
#endif
+
+/*
+ * Feature section common macros
+ *
+ * Note that the entries now contain offsets between the table entry
+ * and the code rather than absolute code pointers in order to be
+ * useable with the vdso shared library. There is also an assumption
+ * that values will be negative, that is, the fixup table has to be
+ * located after the code it fixes up.
+ */
+#ifdef CONFIG_PPC64
+#ifdef __powerpc64__
+/* 64 bits kernel, 64 bits code */
+#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
+99: \
+ .section sect,"a"; \
+ .align 3; \
+98: \
+ .llong msk; \
+ .llong val; \
+ .llong label##b-98b; \
+ .llong 99b-98b; \
+ .previous
+#else /* __powerpc64__ */
+/* 64 bits kernel, 32 bits code (ie. vdso32) */
+#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
+99: \
+ .section sect,"a"; \
+ .align 3; \
+98: \
+ .llong msk; \
+ .llong val; \
+ .long 0xffffffff; \
+ .long label##b-98b; \
+ .long 0xffffffff; \
+ .long 99b-98b; \
+ .previous
+#endif /* !__powerpc64__ */
+#else /* CONFIG_PPC64 */
+/* 32 bits kernel, 32 bits code */
+#define MAKE_FTR_SECTION_ENTRY(msk, val, label, sect) \
+99: \
+ .section sect,"a"; \
+ .align 2; \
+98: \
+ .long msk; \
+ .long val; \
+ .long label##b-98b; \
+ .long 99b-98b; \
+ .previous
+#endif /* !CONFIG_PPC64 */
+
#ifdef __powerpc64__
/* operations for longs and pointers */
Index: linux-cell/include/asm-powerpc/cputable.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/cputable.h 2006-10-12 18:17:37.000000000 +1000
+++ linux-cell/include/asm-powerpc/cputable.h 2006-10-12 18:17:44.000000000 +1000
@@ -432,32 +432,11 @@ static inline int cpu_has_feature(unsign
#ifdef __ASSEMBLY__
#define BEGIN_FTR_SECTION_NESTED(label) label:
-#define BEGIN_FTR_SECTION BEGIN_FTR_SECTION_NESTED(98)
-
-#ifndef __powerpc64__
-#define END_FTR_SECTION_NESTED(msk, val, label) \
-99: \
- .section __ftr_fixup,"a"; \
- .align 2; \
- .long msk; \
- .long val; \
- .long label##b; \
- .long 99b; \
- .previous
-#else /* __powerpc64__ */
+#define BEGIN_FTR_SECTION BEGIN_FTR_SECTION_NESTED(97)
#define END_FTR_SECTION_NESTED(msk, val, label) \
-99: \
- .section __ftr_fixup,"a"; \
- .align 3; \
- .llong msk; \
- .llong val; \
- .llong label##b; \
- .llong 99b; \
- .previous
-#endif /* __powerpc64__ */
-
+ MAKE_FTR_SECTION_ENTRY(msk, val, label, __ftr_fixup)
#define END_FTR_SECTION(msk, val) \
- END_FTR_SECTION_NESTED(msk, val, 98)
+ END_FTR_SECTION_NESTED(msk, val, 97)
#define END_FTR_SECTION_IFSET(msk) END_FTR_SECTION((msk), (msk))
#define END_FTR_SECTION_IFCLR(msk) END_FTR_SECTION((msk), 0)
Index: linux-cell/include/asm-powerpc/firmware.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/firmware.h 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/include/asm-powerpc/firmware.h 2006-10-12 18:17:44.000000000 +1000
@@ -98,17 +98,12 @@ extern int fwnmi_active;
#else /* __ASSEMBLY__ */
-#define BEGIN_FW_FTR_SECTION 96:
-
+#define BEGIN_FW_FTR_SECTION_NESTED(label) label:
+#define BEGIN_FW_FTR_SECTION BEGIN_FW_FTR_SECTION_NESTED(97)
+#define END_FW_FTR_SECTION_NESTED(msk, val, label) \
+ MAKE_FTR_SECTION_ENTRY(msk, val, label, __fw_ftr_fixup)
#define END_FW_FTR_SECTION(msk, val) \
-97: \
- .section __fw_ftr_fixup,"a"; \
- .align 3; \
- .llong msk; \
- .llong val; \
- .llong 96b; \
- .llong 97b; \
- .previous
+ END_FW_FTR_SECTION_NESTED(msk, val, 97)
#define END_FW_FTR_SECTION_IFSET(msk) END_FW_FTR_SECTION((msk), (msk))
#define END_FW_FTR_SECTION_IFCLR(msk) END_FW_FTR_SECTION((msk), 0)
Index: linux-cell/include/asm-powerpc/timex.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/timex.h 2006-10-12 18:08:40.000000000 +1000
+++ linux-cell/include/asm-powerpc/timex.h 2006-10-12 18:17:44.000000000 +1000
@@ -30,13 +30,15 @@ static inline cycles_t get_cycles(void)
ret = 0;
__asm__ __volatile__(
- "98: mftb %0\n"
+ "97: mftb %0\n"
"99:\n"
".section __ftr_fixup,\"a\"\n"
+ ".align 2\n"
+ "98:\n"
" .long %1\n"
" .long 0\n"
- " .long 98b\n"
- " .long 99b\n"
+ " .long 97b-98b\n"
+ " .long 99b-98b\n"
".previous"
: "=r" (ret) : "i" (CPU_FTR_601));
#endif
^ permalink raw reply
* [PATCH 2/4] powerpc: support nested cpu features
From: Benjamin Herrenschmidt @ 2006-10-12 8:29 UTC (permalink / raw)
To: linuxppc-dev list
This patch adds some macros that can be used with an explicit label in
order to nest cpu features. This should be used very careful but is
necessary for the upcoming cell TB fixup.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Index: linux-cell/include/asm-powerpc/cputable.h
===================================================================
--- linux-cell.orig/include/asm-powerpc/cputable.h 2006-10-11 13:20:08.000000000 +1000
+++ linux-cell/include/asm-powerpc/cputable.h 2006-10-11 13:20:26.000000000 +1000
@@ -431,30 +432,34 @@ static inline int cpu_has_feature(unsign
#ifdef __ASSEMBLY__
-#define BEGIN_FTR_SECTION 98:
+#define BEGIN_FTR_SECTION_NESTED(label) label:
+#define BEGIN_FTR_SECTION BEGIN_FTR_SECTION_NESTED(98)
#ifndef __powerpc64__
-#define END_FTR_SECTION(msk, val) \
+#define END_FTR_SECTION_NESTED(msk, val, label) \
99: \
.section __ftr_fixup,"a"; \
.align 2; \
.long msk; \
.long val; \
- .long 98b; \
+ .long label##b; \
.long 99b; \
.previous
#else /* __powerpc64__ */
-#define END_FTR_SECTION(msk, val) \
+#define END_FTR_SECTION_NESTED(msk, val, label) \
99: \
.section __ftr_fixup,"a"; \
.align 3; \
.llong msk; \
.llong val; \
- .llong 98b; \
+ .llong label##b; \
.llong 99b; \
.previous
#endif /* __powerpc64__ */
+#define END_FTR_SECTION(msk, val) \
+ END_FTR_SECTION_NESTED(msk, val, 98)
+
#define END_FTR_SECTION_IFSET(msk) END_FTR_SECTION((msk), (msk))
#define END_FTR_SECTION_IFCLR(msk) END_FTR_SECTION((msk), 0)
#endif /* __ASSEMBLY__ */
^ permalink raw reply
* [PATCH 1/4] powerpc: consolidate feature fixup code
From: Benjamin Herrenschmidt @ 2006-10-12 8:29 UTC (permalink / raw)
To: linuxppc-dev list
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@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@h /* nop */
-3: stw r0,0(r8)
- andi. r10,r4,CPU_FTR_SPLIT_ID_CACHE@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@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;
+
+ fcur = fixup_start;
+ fend = fixup_end;
+
+ for (; 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));
+ }
+ }
+}
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
*/
^ permalink raw reply
* [PATCH 0/4] powerpc: feature fixup updates
From: Benjamin Herrenschmidt @ 2006-10-12 8:29 UTC (permalink / raw)
To: linuxppc-dev list
The following patches are not to be merged yet as I haven't fully tested
them and I still want to do a few changes. I'm posting them for review
here.
They update the feature fixup mecanism to be nicer (C vs. asm), support
some level of nesting, and work with the vdso. This is needed for the
cell TB workaround which is the last patch of that serie
The remaining bits that need to be done before that queue can be merged,
in addition to testing, are:
- add fixup of modules (should be easy. the __ftr_fixup and
__ftr_fw_fixup sections aren't fully filled at build time with modules,
there are relocs for them, so we need to be a bit careful there but it
should just work)
- rework the cell workarounds to use a different method
^ permalink raw reply
* Handling machine check exception
From: ganesh subramonian @ 2006-10-12 4:59 UTC (permalink / raw)
To: linuxppc-dev
Hi,
I am trying to modify the machinecheck exception
handler so that checks caused by data access to a
particular address range can be ignored. In mpc866
there is a register called DAR(Data Address Register)
which gives the address[access to] which caused the
exception. However this is not mentioned in the
MPC8247 manual. Is there some equivalent register for
8247. (It seemed to me that the DAR should be a core
register and hence should be there on 8247 also. but
if i try to read i really dont get the address causing
the error).
Or is there some way i can specify that access to a
particular range of address should not cause a machine
check?? Please help.
thanks
ganesh
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com
^ permalink raw reply
* [PATCH 4/4] powerpc: Add simple memory allocator to bootwrapper
From: Mark A. Greer @ 2006-10-12 1:35 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20061012013223.GA9143@mag.az.mvista.com>
Provide primitive malloc, free, and realloc functions for bootwrapper.
Signed-off-by: Mark A. Greer <mgreer@mvista.com>
---
Makefile | 2
simple_alloc.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 148 insertions(+), 1 deletion(-)
---
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index ef1bec4..895e537 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -41,7 +41,7 @@ zliblinuxheader := zlib.h zconf.h zutil.
$(addprefix $(obj)/,$(zlibheader))
src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c ns16550.c \
- serial.c div64.S util.S $(zlib)
+ serial.c simple_alloc.c div64.S util.S $(zlib)
src-plat := of.c
src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
diff --git a/arch/powerpc/boot/simple_alloc.c b/arch/powerpc/boot/simple_alloc.c
new file mode 100644
index 0000000..478a381
--- /dev/null
+++ b/arch/powerpc/boot/simple_alloc.c
@@ -0,0 +1,147 @@
+/*
+ * Implement primitive realloc(3) functionality.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2006 (c) MontaVista, Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <stddef.h>
+#include "types.h"
+#include "page.h"
+#include "string.h"
+#include "ops.h"
+
+#define ENTRY_BEEN_USED 0x01
+#define ENTRY_IN_USE 0x02
+
+static struct alloc_info {
+ u32 flags;
+ u32 base;
+ u32 size;
+} *alloc_tbl;
+
+static u32 tbl_entries;
+static u32 alloc_min;
+static u32 space_left;
+
+/*
+ * First time an entry is used, its base and size are set.
+ * An entry can be freed and re-malloc'd but its base & size don't change.
+ * Should be smart enough for needs of bootwrapper.
+ */
+static void *simple_malloc(u32 size)
+{
+ u32 i;
+ struct alloc_info *p = alloc_tbl, *prevp = NULL;
+
+ if (size == 0)
+ goto err_out;
+
+ size = _ALIGN_UP(size, alloc_min);
+
+ for (i=0; i<tbl_entries; i++) {
+ if (!(p->flags & ENTRY_BEEN_USED)) { /* never been used */
+ if (size <= space_left) {
+ if (i > 0)
+ p->base = prevp->base + prevp->size;
+ p->size = size;
+ p->flags = ENTRY_BEEN_USED | ENTRY_IN_USE;
+ space_left -= size;
+ return (void *)p->base;
+ }
+ goto err_out; /* not enough space left */
+ }
+ /* reuse an entry keeping same base & size */
+ else if (!(p->flags & ENTRY_IN_USE) && (size <= p->size)) {
+ p->flags |= ENTRY_IN_USE;
+ return (void *)p->base;
+ }
+ prevp = p++;
+ }
+err_out:
+ return NULL;
+}
+
+static struct alloc_info *simple_find_entry(void *ptr)
+{
+ u32 i;
+ struct alloc_info *p = alloc_tbl;
+
+ for (i=0; i<tbl_entries; i++,p++) {
+ if (!(p->flags & ENTRY_BEEN_USED))
+ break;
+ if ((p->flags & ENTRY_IN_USE) && (p->base == (u32)ptr))
+ return p;
+ }
+ return NULL;
+}
+
+static void simple_free(void *ptr)
+{
+ struct alloc_info *p = simple_find_entry(ptr);
+
+ if (p != NULL)
+ p->flags &= ~ENTRY_IN_USE;
+}
+
+/*
+ * Change size of area pointed to by 'ptr' to 'size'.
+ * If 'ptr' is NULL, then its a malloc(). If 'size' is 0, then its a free().
+ * 'ptr' must be NULL or a value previously returned by simple_realloc().
+ */
+static void *simple_realloc(void *ptr, unsigned long size)
+{
+ struct alloc_info *p;
+ void *new;
+
+ if (size == 0) {
+ simple_free(ptr);
+ return NULL;
+ }
+
+ /* also malloc if ptr didn't come from simple_malloc/realloc */
+ if ((ptr == NULL) || ((p = simple_find_entry(ptr)) == NULL))
+ return simple_malloc(size);
+
+ if (size <= p->size) /* fits in current block */
+ return ptr;
+
+ new = simple_malloc(size);
+ memcpy(new, ptr, p->size);
+ simple_free(ptr);
+ return new;
+}
+
+/*
+ * Returns addr of first byte after heap so caller can see if it took
+ * too much space. If so, change args & try again.
+ */
+void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
+ u32 max_allocs)
+{
+ u32 heap_base, tbl_size;
+
+ heap_size = _ALIGN_UP(heap_size, granularity);
+ alloc_min = granularity;
+ tbl_entries = max_allocs;
+
+ tbl_size = tbl_entries * sizeof(struct alloc_info);
+
+ alloc_tbl = (struct alloc_info *)_ALIGN_UP((unsigned long)base, 8);
+ memset(alloc_tbl, 0, tbl_size);
+
+ heap_base = _ALIGN_UP((u32)alloc_tbl + tbl_size, alloc_min);
+
+ alloc_tbl[0].base = heap_base;
+ space_left = heap_size;
+
+ platform_ops.malloc = simple_malloc;
+ platform_ops.free = simple_free;
+ platform_ops.realloc = simple_realloc;
+
+ return (void *)(heap_base + heap_size);
+}
^ permalink raw reply related
* [PATCH 3/4] powerpc: Add non-OF serial console support
From: Mark A. Greer @ 2006-10-12 1:35 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20061012013223.GA9143@mag.az.mvista.com>
Add serial console support for non-OF systems. There is a generic serial
console layer which calls a serial console driver. Included is the serial
console driver for the ns16550 class of uarts. Necessary support routines
are added as well.
Signed-off-by: Mark A. Greer <mgreer@mvista.com>
---
Makefile | 4 -
io.h | 53 +++++++++++++++++++++++
ns16550.c | 76 +++++++++++++++++++++++++++++++++
serial.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
util.S | 101 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 374 insertions(+), 2 deletions(-)
---
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 8660cc5..ef1bec4 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -40,8 +40,8 @@ zliblinuxheader := zlib.h zconf.h zutil.
$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \
$(addprefix $(obj)/,$(zlibheader))
-src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c div64.S \
- $(zlib)
+src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c ns16550.c \
+ serial.c div64.S util.S $(zlib)
src-plat := of.c
src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
diff --git a/arch/powerpc/boot/io.h b/arch/powerpc/boot/io.h
new file mode 100644
index 0000000..32974ed
--- /dev/null
+++ b/arch/powerpc/boot/io.h
@@ -0,0 +1,53 @@
+#ifndef _IO_H
+#define __IO_H
+/*
+ * Low-level I/O routines.
+ *
+ * Copied from <file:include/asm-powerpc/io.h> (which has no copyright)
+ */
+static inline int in_8(const volatile unsigned char *addr)
+{
+ int ret;
+
+ __asm__ __volatile__("lbz%U1%X1 %0,%1; twi 0,%0,0; isync"
+ : "=r" (ret) : "m" (*addr));
+ return ret;
+}
+
+static inline void out_8(volatile unsigned char *addr, int val)
+{
+ __asm__ __volatile__("stb%U0%X0 %1,%0; sync"
+ : "=m" (*addr) : "r" (val));
+}
+
+static inline unsigned in_le32(const volatile unsigned *addr)
+{
+ unsigned ret;
+
+ __asm__ __volatile__("lwbrx %0,0,%1; twi 0,%0,0; isync"
+ : "=r" (ret) : "r" (addr), "m" (*addr));
+ return ret;
+}
+
+static inline unsigned in_be32(const volatile unsigned *addr)
+{
+ unsigned ret;
+
+ __asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync"
+ : "=r" (ret) : "m" (*addr));
+ return ret;
+}
+
+static inline void out_le32(volatile unsigned *addr, int val)
+{
+ __asm__ __volatile__("stwbrx %1,0,%2; sync" : "=m" (*addr)
+ : "r" (val), "r" (addr));
+}
+
+static inline void out_be32(volatile unsigned *addr, int val)
+{
+ __asm__ __volatile__("stw%U0%X0 %1,%0; sync"
+ : "=m" (*addr) : "r" (val));
+}
+
+#endif /* _IO_H */
diff --git a/arch/powerpc/boot/ns16550.c b/arch/powerpc/boot/ns16550.c
new file mode 100644
index 0000000..e066942
--- /dev/null
+++ b/arch/powerpc/boot/ns16550.c
@@ -0,0 +1,76 @@
+/*
+ * 16550 serial console support.
+ *
+ * Original copied from <file:arch/ppc/boot/common/ns16550.c>
+ * (which had no copyright)
+ * Modifications: 2006 (c) MontaVista Software, Inc.
+ *
+ * Modified by: Mark A. Greer <mgreer@mvista.com>
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+
+#define UART_DLL 0 /* Out: Divisor Latch Low */
+#define UART_DLM 1 /* Out: Divisor Latch High */
+#define UART_FCR 2 /* Out: FIFO Control Register */
+#define UART_LCR 3 /* Out: Line Control Register */
+#define UART_MCR 4 /* Out: Modem Control Register */
+#define UART_LSR 5 /* In: Line Status Register */
+#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
+#define UART_LSR_DR 0x01 /* Receiver data ready */
+#define UART_MSR 6 /* In: Modem Status Register */
+#define UART_SCR 7 /* I/O: Scratch Register */
+
+static unsigned char *reg_base;
+static u8 reg_shift;
+
+static int ns16550_open(void)
+{
+ out_8(reg_base + (UART_FCR << reg_shift), 0x06);
+ return 0;
+}
+
+static void ns16550_putc(unsigned char c)
+{
+ while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_THRE) == 0);
+ out_8(reg_base, c);
+}
+
+static unsigned char ns16550_getc(void)
+{
+ while ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) == 0);
+ return in_8(reg_base);
+}
+
+static u8 ns16550_tstc(void)
+{
+ return ((in_8(reg_base + (UART_LSR << reg_shift)) & UART_LSR_DR) != 0);
+}
+
+int ns16550_console_init(void *devp, struct serial_console_data *scdp)
+{
+ u32 reg[2];
+ int n;
+
+ n = getprop(devp, "virtual-reg", ®, sizeof(reg)) / 4;
+ if (n < 1)
+ return -1;
+ reg_base = (unsigned char *)((n == 1) ? reg[0] : reg[0] | reg[1]);
+
+ if (getprop(devp, "reg_shift", ®_shift, sizeof(reg_shift))
+ != sizeof(reg_shift))
+ reg_shift = 0;
+
+ scdp->open = ns16550_open;
+ scdp->putc = ns16550_putc;
+ scdp->getc = ns16550_getc;
+ scdp->tstc = ns16550_tstc;
+ scdp->close = NULL;
+
+ return 0;
+}
diff --git a/arch/powerpc/boot/serial.c b/arch/powerpc/boot/serial.c
new file mode 100644
index 0000000..e8de4cf
--- /dev/null
+++ b/arch/powerpc/boot/serial.c
@@ -0,0 +1,142 @@
+/*
+ * Generic serial console support
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Code in serial_edit_cmdline() copied from <file:arch/ppc/boot/simple/misc.c>
+ * and was written by Matt Porter <mporter@kernel.crashing.org>.
+ *
+ * 2001,2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+
+extern void udelay(long delay);
+
+static int serial_open(void)
+{
+ struct serial_console_data *scdp = console_ops.data;
+ return scdp->open();
+}
+
+static void serial_write(char *buf, int len)
+{
+ struct serial_console_data *scdp = console_ops.data;
+
+ while (*buf != '\0')
+ scdp->putc(*buf++);
+}
+
+static void serial_edit_cmdline(char *buf, int len)
+{
+ int timer = 0, count;
+ char ch, *cp;
+ struct serial_console_data *scdp = console_ops.data;
+
+ cp = buf;
+ count = strlen(buf);
+ cp = &buf[count];
+ count++;
+
+ while (timer++ < 5*1000) {
+ if (scdp->tstc()) {
+ while (((ch = scdp->getc()) != '\n') && (ch != '\r')) {
+ /* Test for backspace/delete */
+ if ((ch == '\b') || (ch == '\177')) {
+ if (cp != buf) {
+ cp--;
+ count--;
+ printf("\b \b");
+ }
+ /* Test for ^x/^u (and wipe the line) */
+ } else if ((ch == '\030') || (ch == '\025')) {
+ while (cp != buf) {
+ cp--;
+ count--;
+ printf("\b \b");
+ }
+ } else if (count < len) {
+ *cp++ = ch;
+ count++;
+ scdp->putc(ch);
+ }
+ }
+ break; /* Exit 'timer' loop */
+ }
+ udelay(1000); /* 1 msec */
+ }
+ *cp = 0;
+}
+
+static void serial_close(void)
+{
+ struct serial_console_data *scdp = console_ops.data;
+
+ if (scdp->close)
+ scdp->close();
+}
+
+static void *serial_get_stdout_devp(void)
+{
+ void *devp;
+ char devtype[MAX_PROP_LEN];
+ char path[MAX_PATH_LEN];
+
+ devp = finddevice("/chosen");
+ if (devp == NULL)
+ goto err_out;
+
+ if (getprop(devp, "linux,stdout-path", path, MAX_PATH_LEN) > 0) {
+ devp = finddevice(path);
+ if (devp == NULL)
+ goto err_out;
+
+ if ((getprop(devp, "device_type", devtype, sizeof(devtype)) > 0)
+ && !strcmp(devtype, "serial"))
+ return devp;
+ }
+err_out:
+ return NULL;
+}
+
+static struct serial_console_data serial_cd;
+
+/* Node's "compatible" property determines which serial driver to use */
+int serial_console_init(void)
+{
+ void *devp;
+ int rc = -1;
+ char compat[MAX_PROP_LEN];
+
+ devp = serial_get_stdout_devp();
+ if (devp == NULL)
+ goto err_out;
+
+ if (getprop(devp, "compatible", compat, sizeof(compat)) < 0)
+ goto err_out;
+
+ if (!strcmp(compat, "ns16550"))
+ rc = ns16550_console_init(devp, &serial_cd);
+
+ /* Add other serial console driver calls here */
+
+ if (!rc) {
+ console_ops.open = serial_open;
+ console_ops.write = serial_write;
+ console_ops.edit_cmdline = serial_edit_cmdline;
+ console_ops.close = serial_close;
+ console_ops.data = &serial_cd;
+
+ return 0;
+ }
+err_out:
+ return -1;
+}
diff --git a/arch/powerpc/boot/util.S b/arch/powerpc/boot/util.S
new file mode 100644
index 0000000..b8e1c23
--- /dev/null
+++ b/arch/powerpc/boot/util.S
@@ -0,0 +1,101 @@
+/*
+ * Copied from <file:arch/powerpc/kernel/misc_32.S>
+ *
+ * This file contains miscellaneous low-level functions.
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
+ * and Paul Mackerras.
+ *
+ * kexec bits:
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * 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.
+ *
+ */
+#include "ppc_asm.h"
+
+#define SPRN_PVR 0x11F /* Processor Version Register */
+
+ .text
+/*
+ * complement mask on the msr then "or" some values on.
+ * _nmask_and_or_msr(nmask, value_to_or)
+ */
+ .globl _nmask_and_or_msr
+_nmask_and_or_msr:
+ mfmsr r0 /* Get current msr */
+ andc r0,r0,r3 /* And off the bits set in r3 (first parm) */
+ or r0,r0,r4 /* Or on the bits in r4 (second parm) */
+ SYNC /* Some chip revs have problems here... */
+ mtmsr r0 /* Update machine state */
+ isync
+ blr /* Done */
+
+/* udelay (on non-601 processors) needs to know the period of the
+ * timebase in nanoseconds. This used to be hardcoded to be 60ns
+ * (period of 66MHz/4). Now a variable is used that is initialized to
+ * 60 for backward compatibility, but it can be overridden as necessary
+ * with code something like this:
+ * extern unsigned long timebase_period_ns;
+ * timebase_period_ns = 1000000000 / bd->bi_tbfreq;
+ */
+ .data
+ .globl timebase_period_ns
+timebase_period_ns:
+ .long 60
+
+ .text
+/*
+ * Delay for a number of microseconds
+ */
+ .globl udelay
+udelay:
+ mfspr r4,SPRN_PVR
+ srwi r4,r4,16
+ cmpwi 0,r4,1 /* 601 ? */
+ bne .udelay_not_601
+00: li r0,86 /* Instructions / microsecond? */
+ mtctr r0
+10: addi r0,r0,0 /* NOP */
+ bdnz 10b
+ subic. r3,r3,1
+ bne 00b
+ blr
+
+.udelay_not_601:
+ mulli r4,r3,1000 /* nanoseconds */
+ /* Change r4 to be the number of ticks using:
+ * (nanoseconds + (timebase_period_ns - 1 )) / timebase_period_ns
+ * timebase_period_ns defaults to 60 (16.6MHz) */
+ mflr r5
+ bl 0f
+0: mflr r6
+ mtlr r5
+ lis r5,0b@ha
+ addi r5,r5,0b@l
+ subf r5,r5,r6 /* In case we're relocated */
+ addis r5,r5,timebase_period_ns@ha
+ lwz r5,timebase_period_ns@l(r5)
+ add r4,r4,r5
+ addi r4,r4,-1
+ divw r4,r4,r5 /* BUS ticks */
+1: mftbu r5
+ mftb r6
+ mftbu r7
+ cmpw 0,r5,r7
+ bne 1b /* Get [synced] base time */
+ addc r9,r6,r4 /* Compute end time */
+ addze r8,r5
+2: mftbu r5
+ cmpw 0,r5,r8
+ blt 2b
+ bgt 3f
+ mftb r6
+ cmpw 0,r6,r9
+ blt 2b
+3: blr
^ permalink raw reply related
* [PATCH 2/4] powerpc: Add flatdevtree source
From: Mark A. Greer @ 2006-10-12 1:34 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20061012013223.GA9143@mag.az.mvista.com>
Add the latest version of the flatdevtree code and corresponding glue.
A phandle table now tracks values returned by ft_find_device().
The value returned by ft_find_device() is a phandle which is really
an index into the phandle table. The phandle table contains the address
of the corresponding node. When the flat dt is edited/moved, the node
pointers in the phandle table are updated accordingly so no phandles kept
by the caller become stale.
Signed-off-by: Mark A. Greer <mgreer@mvista.com>
---
Makefile | 3
flatdevtree.c | 876 +++++++++++++++++++++++++++++++++++++++++++++++++++++
flatdevtree.h | 62 +++
flatdevtree_env.h | 47 ++
flatdevtree_misc.c | 56 +++
5 files changed, 1042 insertions(+), 2 deletions(-)
---
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 37ddfca..8660cc5 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -40,7 +40,8 @@ zliblinuxheader := zlib.h zconf.h zutil.
$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \
$(addprefix $(obj)/,$(zlibheader))
-src-wlib := string.S stdio.c main.c div64.S $(zlib)
+src-wlib := string.S stdio.c main.c flatdevtree.c flatdevtree_misc.c div64.S \
+ $(zlib)
src-plat := of.c
src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
diff --git a/arch/powerpc/boot/flatdevtree.c b/arch/powerpc/boot/flatdevtree.c
new file mode 100644
index 0000000..0d24f50
--- /dev/null
+++ b/arch/powerpc/boot/flatdevtree.c
@@ -0,0 +1,876 @@
+/*
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright Pantelis Antoniou 2006
+ * Copyright (C) IBM Corporation 2006
+ *
+ * Authors: Pantelis Antoniou <pantelis@embeddedalley.com>
+ * Hollis Blanchard <hollisb@us.ibm.com>
+ * Mark A. Greer <mgreer@mvista.com>
+ * Paul Mackerras <paulus@samba.org>
+ */
+
+#include <string.h>
+#include <stddef.h>
+#include "flatdevtree.h"
+#include "flatdevtree_env.h"
+
+#define _ALIGN(x, al) (((x) + (al) - 1) & ~((al) - 1))
+
+/* Routines for keeping node ptrs returned by ft_find_device current */
+/* First entry not used b/c it would return 0 and be taken as NULL/error */
+static void *ft_node_add(struct ft_cxt *cxt, char *node)
+{
+ unsigned int i;
+
+ for (i = 1; i < cxt->nodes_used; i++) /* already there? */
+ if (cxt->node_tbl[i] == node)
+ return (void *)i;
+
+ if (cxt->nodes_used < cxt->node_max) {
+ cxt->node_tbl[cxt->nodes_used] = node;
+ return (void *)cxt->nodes_used++;
+ }
+
+ return NULL;
+}
+
+static char *ft_node_ph2node(struct ft_cxt *cxt, const void *phandle)
+{
+ unsigned int i = (unsigned int)phandle;
+
+ if (i < cxt->nodes_used)
+ return cxt->node_tbl[i];
+ return NULL;
+}
+
+static void ft_node_update_before(struct ft_cxt *cxt, char *addr, int shift)
+{
+ unsigned int i;
+
+ if (shift == 0)
+ return;
+
+ for (i = 1; i < cxt->nodes_used; i++)
+ if (cxt->node_tbl[i] < addr)
+ cxt->node_tbl[i] += shift;
+}
+
+static void ft_node_update_after(struct ft_cxt *cxt, char *addr, int shift)
+{
+ unsigned int i;
+
+ if (shift == 0)
+ return;
+
+ for (i = 1; i < cxt->nodes_used; i++)
+ if (cxt->node_tbl[i] >= addr)
+ cxt->node_tbl[i] += shift;
+}
+
+/* Struct used to return info from ft_next() */
+struct ft_atom {
+ u32 tag;
+ const char *name;
+ void *data;
+ u32 size;
+};
+
+/* Set ptrs to current one's info; return addr of next one */
+static char *ft_next(struct ft_cxt *cxt, char *p, struct ft_atom *ret)
+{
+ u32 sz;
+
+ if (p >= cxt->rgn[FT_STRUCT].start + cxt->rgn[FT_STRUCT].size)
+ return NULL;
+
+ ret->tag = be32_to_cpu(*(u32 *) p);
+ p += 4;
+
+ switch (ret->tag) { /* Tag */
+ case OF_DT_BEGIN_NODE:
+ ret->name = p;
+ ret->data = (void *)(p - 4); /* start of node */
+ p += _ALIGN(strlen(p) + 1, 4);
+ break;
+ case OF_DT_PROP:
+ ret->size = sz = be32_to_cpu(*(u32 *) p);
+ ret->name = cxt->str_anchor + be32_to_cpu(*(u32 *) (p + 4));
+ ret->data = (void *)(p + 8);
+ p += 8 + _ALIGN(sz, 4);
+ break;
+ case OF_DT_END_NODE:
+ case OF_DT_NOP:
+ break;
+ case OF_DT_END:
+ default:
+ p = NULL;
+ break;
+ }
+
+ return p;
+}
+
+#define HDR_SIZE _ALIGN(sizeof(struct boot_param_header), 8)
+#define EXPAND_INCR 1024 /* alloc this much extra when expanding */
+
+/* See if the regions are in the standard order and non-overlapping */
+static int ft_ordered(struct ft_cxt *cxt)
+{
+ char *p = (char *)cxt->bph + HDR_SIZE;
+ enum ft_rgn_id r;
+
+ for (r = FT_RSVMAP; r <= FT_STRINGS; ++r) {
+ if (p > cxt->rgn[r].start)
+ return 0;
+ p = cxt->rgn[r].start + cxt->rgn[r].size;
+ }
+ return p <= (char *)cxt->bph + cxt->max_size;
+}
+
+/* Copy the tree to a newly-allocated region and put things in order */
+static int ft_reorder(struct ft_cxt *cxt, int nextra)
+{
+ unsigned long tot;
+ enum ft_rgn_id r;
+ char *p, *pend;
+ int stroff;
+
+ tot = HDR_SIZE + EXPAND_INCR;
+ for (r = FT_RSVMAP; r <= FT_STRINGS; ++r)
+ tot += cxt->rgn[r].size;
+ if (nextra > 0)
+ tot += nextra;
+ tot = _ALIGN(tot, 8);
+
+ if (!cxt->realloc)
+ return 0;
+ p = cxt->realloc(NULL, tot);
+ if (!p)
+ return 0;
+
+ memcpy(p, cxt->bph, sizeof(struct boot_param_header));
+ /* offsets get fixed up later */
+
+ cxt->bph = (struct boot_param_header *)p;
+ cxt->max_size = tot;
+ pend = p + tot;
+ p += HDR_SIZE;
+
+ memcpy(p, cxt->rgn[FT_RSVMAP].start, cxt->rgn[FT_RSVMAP].size);
+ cxt->rgn[FT_RSVMAP].start = p;
+ p += cxt->rgn[FT_RSVMAP].size;
+
+ memcpy(p, cxt->rgn[FT_STRUCT].start, cxt->rgn[FT_STRUCT].size);
+ ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start,
+ p - cxt->rgn[FT_STRUCT].start);
+ cxt->rgn[FT_STRUCT].start = p;
+
+ p = pend - cxt->rgn[FT_STRINGS].size;
+ memcpy(p, cxt->rgn[FT_STRINGS].start, cxt->rgn[FT_STRINGS].size);
+ stroff = cxt->str_anchor - cxt->rgn[FT_STRINGS].start;
+ cxt->rgn[FT_STRINGS].start = p;
+ cxt->str_anchor = p + stroff;
+
+ cxt->isordered = 1;
+ return 1;
+}
+
+static inline char *prev_end(struct ft_cxt *cxt, enum ft_rgn_id r)
+{
+ if (r > FT_RSVMAP)
+ return cxt->rgn[r - 1].start + cxt->rgn[r - 1].size;
+ return (char *)cxt->bph + HDR_SIZE;
+}
+
+static inline char *next_start(struct ft_cxt *cxt, enum ft_rgn_id r)
+{
+ if (r < FT_STRINGS)
+ return cxt->rgn[r + 1].start;
+ return (char *)cxt->bph + cxt->max_size;
+}
+
+/*
+ * See if we can expand region rgn by nextra bytes by using up
+ * free space after or before the region.
+ */
+static int ft_shuffle(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
+ int nextra)
+{
+ char *p = *pp;
+ char *rgn_start, *rgn_end;
+
+ rgn_start = cxt->rgn[rgn].start;
+ rgn_end = rgn_start + cxt->rgn[rgn].size;
+ if (nextra <= 0 || rgn_end + nextra <= next_start(cxt, rgn)) {
+ /* move following stuff */
+ if (p < rgn_end) {
+ if (nextra < 0)
+ memmove(p, p - nextra, rgn_end - p + nextra);
+ else
+ memmove(p + nextra, p, rgn_end - p);
+ if (rgn == FT_STRUCT)
+ ft_node_update_after(cxt, p, nextra);
+ }
+ cxt->rgn[rgn].size += nextra;
+ if (rgn == FT_STRINGS)
+ /* assumes strings only added at beginning */
+ cxt->str_anchor += nextra;
+ return 1;
+ }
+ if (prev_end(cxt, rgn) <= rgn_start - nextra) {
+ /* move preceding stuff */
+ if (p > rgn_start) {
+ memmove(rgn_start - nextra, rgn_start, p - rgn_start);
+ if (rgn == FT_STRUCT)
+ ft_node_update_before(cxt, p, -nextra);
+ }
+ *p -= nextra;
+ cxt->rgn[rgn].start -= nextra;
+ cxt->rgn[rgn].size += nextra;
+ return 1;
+ }
+ return 0;
+}
+
+static int ft_make_space(struct ft_cxt *cxt, char **pp, enum ft_rgn_id rgn,
+ int nextra)
+{
+ unsigned long size, ssize, tot;
+ char *str, *next;
+ enum ft_rgn_id r;
+
+ if (!cxt->isordered && !ft_reorder(cxt, nextra))
+ return 0;
+ if (ft_shuffle(cxt, pp, rgn, nextra))
+ return 1;
+
+ /* See if there is space after the strings section */
+ ssize = cxt->rgn[FT_STRINGS].size;
+ if (cxt->rgn[FT_STRINGS].start + ssize
+ < (char *)cxt->bph + cxt->max_size) {
+ /* move strings up as far as possible */
+ str = (char *)cxt->bph + cxt->max_size - ssize;
+ cxt->str_anchor += str - cxt->rgn[FT_STRINGS].start;
+ memmove(str, cxt->rgn[FT_STRINGS].start, ssize);
+ cxt->rgn[FT_STRINGS].start = str;
+ /* enough space now? */
+ if (rgn >= FT_STRUCT && ft_shuffle(cxt, pp, rgn, nextra))
+ return 1;
+ }
+
+ /* how much total free space is there following this region? */
+ tot = 0;
+ for (r = rgn; r < FT_STRINGS; ++r) {
+ char *r_end = cxt->rgn[r].start + cxt->rgn[r].size;
+ tot += next_start(cxt, rgn) - r_end;
+ }
+
+ /* cast is to shut gcc up; we know nextra >= 0 */
+ if (tot < (unsigned int)nextra) {
+ /* have to reallocate */
+ char *newp, *oldp, *new_start;
+ int shift;
+
+ if (!cxt->realloc)
+ return 0;
+ size = _ALIGN(cxt->max_size + (nextra - tot) + EXPAND_INCR, 8);
+ newp = cxt->realloc(cxt->bph, size);
+ if (!newp)
+ return 0;
+ cxt->max_size = size;
+ oldp = (char *)cxt->bph;
+ shift = newp - oldp;
+
+ if (shift != 0) { /* realloc can return same addr */
+ cxt->bph = (struct boot_param_header *)newp;
+ memmove(newp, oldp, sizeof(struct boot_param_header));
+ ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start,
+ shift);
+ for (r = FT_RSVMAP; r <= FT_STRUCT; ++r) {
+ new_start = cxt->rgn[r].start + shift;
+ memmove(new_start, cxt->rgn[r].start,
+ cxt->rgn[r].size);
+ cxt->rgn[r].start = new_start;
+ }
+ *pp += shift;
+ }
+
+ /* move strings up to the end */
+ str = newp + size - ssize;
+ cxt->str_anchor += str - cxt->rgn[FT_STRINGS].start;
+ memmove(str, cxt->rgn[FT_STRINGS].start, ssize);
+ cxt->rgn[FT_STRINGS].start = str;
+
+ if (ft_shuffle(cxt, pp, rgn, nextra))
+ return 1;
+ }
+
+ /* must be FT_RSVMAP and we need to move FT_STRUCT up */
+ if (rgn == FT_RSVMAP) {
+ next = cxt->rgn[FT_RSVMAP].start + cxt->rgn[FT_RSVMAP].size
+ + nextra;
+ ssize = cxt->rgn[FT_STRUCT].size;
+ if (next + ssize >= cxt->rgn[FT_STRINGS].start)
+ return 0; /* "can't happen" */
+ memmove(next, cxt->rgn[FT_STRUCT].start, ssize);
+ ft_node_update_after(cxt, cxt->rgn[FT_STRUCT].start, nextra);
+ cxt->rgn[FT_STRUCT].start = next;
+
+ if (ft_shuffle(cxt, pp, rgn, nextra))
+ return 1;
+ }
+
+ return 0; /* "can't happen" */
+}
+
+static void ft_put_word(struct ft_cxt *cxt, u32 v)
+{
+ *(u32 *) cxt->p = cpu_to_be32(v);
+ cxt->p += 4;
+}
+
+static void ft_put_bin(struct ft_cxt *cxt, const void *data, unsigned int sz)
+{
+ unsigned long sza = _ALIGN(sz, 4);
+
+ /* zero out the alignment gap if necessary */
+ if (sz < sza)
+ *(u32 *) (cxt->p + sza - 4) = 0;
+
+ /* copy in the data */
+ memcpy(cxt->p, data, sz);
+
+ cxt->p += sza;
+}
+
+int ft_begin_node(struct ft_cxt *cxt, const char *name)
+{
+ unsigned long nlen = strlen(name) + 1;
+ unsigned long len = 8 + _ALIGN(nlen, 4);
+
+ if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, len))
+ return -1;
+ ft_put_word(cxt, OF_DT_BEGIN_NODE);
+ ft_put_bin(cxt, name, strlen(name) + 1);
+ return 0;
+}
+
+void ft_end_node(struct ft_cxt *cxt)
+{
+ ft_put_word(cxt, OF_DT_END_NODE);
+}
+
+void ft_nop(struct ft_cxt *cxt)
+{
+ if (ft_make_space(cxt, &cxt->p, FT_STRUCT, 4))
+ ft_put_word(cxt, OF_DT_NOP);
+}
+
+#define NO_STRING 0x7fffffff
+
+static int lookup_string(struct ft_cxt *cxt, const char *name)
+{
+ char *p, *end;
+
+ p = cxt->rgn[FT_STRINGS].start;
+ end = p + cxt->rgn[FT_STRINGS].size;
+ while (p < end) {
+ if (strcmp(p, (char *)name) == 0)
+ return p - cxt->str_anchor;
+ p += strlen(p) + 1;
+ }
+
+ return NO_STRING;
+}
+
+/* lookup string and insert if not found */
+static int map_string(struct ft_cxt *cxt, const char *name)
+{
+ int off;
+ char *p;
+
+ off = lookup_string(cxt, name);
+ if (off != NO_STRING)
+ return off;
+ p = cxt->rgn[FT_STRINGS].start;
+ if (!ft_make_space(cxt, &p, FT_STRINGS, strlen(name) + 1))
+ return NO_STRING;
+ strcpy(p, name);
+ return p - cxt->str_anchor;
+}
+
+int ft_prop(struct ft_cxt *cxt, const char *name, const void *data,
+ unsigned int sz)
+{
+ int off, len;
+
+ off = lookup_string(cxt, name);
+ if (off == NO_STRING)
+ return -1;
+
+ len = 12 + _ALIGN(sz, 4);
+ if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, len))
+ return -1;
+
+ ft_put_word(cxt, OF_DT_PROP);
+ ft_put_word(cxt, sz);
+ ft_put_word(cxt, off);
+ ft_put_bin(cxt, data, sz);
+ return 0;
+}
+
+int ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str)
+{
+ return ft_prop(cxt, name, str, strlen(str) + 1);
+}
+
+int ft_prop_int(struct ft_cxt *cxt, const char *name, unsigned int val)
+{
+ u32 v = cpu_to_be32((u32) val);
+
+ return ft_prop(cxt, name, &v, 4);
+}
+
+/* Calculate the size of the reserved map */
+static unsigned long rsvmap_size(struct ft_cxt *cxt)
+{
+ struct ft_reserve *res;
+
+ res = (struct ft_reserve *)cxt->rgn[FT_RSVMAP].start;
+ while (res->start || res->len)
+ ++res;
+ return (char *)(res + 1) - cxt->rgn[FT_RSVMAP].start;
+}
+
+/* Calculate the size of the struct region by stepping through it */
+static unsigned long struct_size(struct ft_cxt *cxt)
+{
+ char *p = cxt->rgn[FT_STRUCT].start;
+ char *next;
+ struct ft_atom atom;
+
+ /* make check in ft_next happy */
+ if (cxt->rgn[FT_STRUCT].size == 0)
+ cxt->rgn[FT_STRUCT].size = 0xfffffffful - (unsigned long)p;
+
+ while ((next = ft_next(cxt, p, &atom)) != NULL)
+ p = next;
+ return p + 4 - cxt->rgn[FT_STRUCT].start;
+}
+
+/* add `adj' on to all string offset values in the struct area */
+static void adjust_string_offsets(struct ft_cxt *cxt, int adj)
+{
+ char *p = cxt->rgn[FT_STRUCT].start;
+ char *next;
+ struct ft_atom atom;
+ int off;
+
+ while ((next = ft_next(cxt, p, &atom)) != NULL) {
+ if (atom.tag == OF_DT_PROP) {
+ off = be32_to_cpu(*(u32 *) (p + 8));
+ *(u32 *) (p + 8) = cpu_to_be32(off + adj);
+ }
+ p = next;
+ }
+}
+
+/* start construction of the flat OF tree from scratch */
+void ft_begin(struct ft_cxt *cxt, void *blob, unsigned int max_size,
+ void *(*realloc_fn) (void *, unsigned long))
+{
+ struct boot_param_header *bph = blob;
+ char *p;
+ struct ft_reserve *pres;
+
+ /* clear the cxt */
+ memset(cxt, 0, sizeof(*cxt));
+
+ cxt->bph = bph;
+ cxt->max_size = max_size;
+ cxt->realloc = realloc_fn;
+ cxt->isordered = 1;
+
+ /* zero everything in the header area */
+ memset(bph, 0, sizeof(*bph));
+
+ bph->magic = cpu_to_be32(OF_DT_HEADER);
+ bph->version = cpu_to_be32(0x10);
+ bph->last_comp_version = cpu_to_be32(0x10);
+
+ /* start pointers */
+ cxt->rgn[FT_RSVMAP].start = p = blob + HDR_SIZE;
+ cxt->rgn[FT_RSVMAP].size = sizeof(struct ft_reserve);
+ pres = (struct ft_reserve *)p;
+ cxt->rgn[FT_STRUCT].start = p += sizeof(struct ft_reserve);
+ cxt->rgn[FT_STRUCT].size = 4;
+ cxt->rgn[FT_STRINGS].start = blob + max_size;
+ cxt->rgn[FT_STRINGS].size = 0;
+
+ /* init rsvmap and struct */
+ pres->start = 0;
+ pres->len = 0;
+ *(u32 *) p = cpu_to_be32(OF_DT_END);
+
+ cxt->str_anchor = blob;
+}
+
+/* open up an existing blob to be examined or modified */
+int ft_open(struct ft_cxt *cxt, void *blob, unsigned int max_size,
+ unsigned int max_find_device,
+ void *(*realloc_fn) (void *, unsigned long))
+{
+ struct boot_param_header *bph = blob;
+
+ /* can't cope with version < 16 */
+ if (be32_to_cpu(bph->version) < 16)
+ return -1;
+
+ /* clear the cxt */
+ memset(cxt, 0, sizeof(*cxt));
+
+ /* alloc node_tbl to track node ptrs returned by ft_find_device */
+ ++max_find_device;
+ cxt->node_tbl = realloc_fn(NULL, max_find_device * sizeof(char *));
+ if (!cxt->node_tbl)
+ return -1;
+ memset(cxt->node_tbl, 0, max_find_device * sizeof(char *));
+ cxt->node_max = max_find_device;
+ cxt->nodes_used = 1; /* don't use idx 0 b/c looks like NULL */
+
+ cxt->bph = bph;
+ cxt->max_size = max_size;
+ cxt->realloc = realloc_fn;
+
+ cxt->rgn[FT_RSVMAP].start = blob + be32_to_cpu(bph->off_mem_rsvmap);
+ cxt->rgn[FT_RSVMAP].size = rsvmap_size(cxt);
+ cxt->rgn[FT_STRUCT].start = blob + be32_to_cpu(bph->off_dt_struct);
+ cxt->rgn[FT_STRUCT].size = struct_size(cxt);
+ cxt->rgn[FT_STRINGS].start = blob + be32_to_cpu(bph->off_dt_strings);
+ cxt->rgn[FT_STRINGS].size = be32_to_cpu(bph->dt_strings_size);
+ cxt->isordered = ft_ordered(cxt);
+
+ cxt->p = cxt->rgn[FT_STRUCT].start;
+ cxt->str_anchor = cxt->rgn[FT_STRINGS].start;
+
+ return 0;
+}
+
+/* add a reserver physical area to the rsvmap */
+int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size)
+{
+ char *p;
+ struct ft_reserve *pres;
+
+ p = cxt->rgn[FT_RSVMAP].start + cxt->rgn[FT_RSVMAP].size
+ - sizeof(struct ft_reserve);
+ if (!ft_make_space(cxt, &p, FT_RSVMAP, sizeof(struct ft_reserve)))
+ return -1;
+
+ pres = (struct ft_reserve *)p;
+ pres->start = cpu_to_be64(physaddr);
+ pres->len = cpu_to_be64(size);
+
+ return 0;
+}
+
+void ft_begin_tree(struct ft_cxt *cxt)
+{
+ cxt->p = cxt->rgn[FT_STRUCT].start;
+}
+
+void ft_end_tree(struct ft_cxt *cxt)
+{
+ struct boot_param_header *bph = cxt->bph;
+ char *p, *oldstr, *str, *endp;
+ unsigned long ssize;
+
+ if (!cxt->isordered)
+ return; /* we haven't touched anything */
+
+ /* adjust string offsets */
+ oldstr = cxt->rgn[FT_STRINGS].start;
+ adjust_string_offsets(cxt, cxt->str_anchor - oldstr);
+
+ /* make strings end on 8-byte boundary */
+ ssize = cxt->rgn[FT_STRINGS].size;
+ endp = (char *)_ALIGN((unsigned long)cxt->rgn[FT_STRUCT].start
+ + cxt->rgn[FT_STRUCT].size + ssize, 8);
+ str = endp - ssize;
+
+ /* move strings down to end of structs */
+ memmove(str, oldstr, ssize);
+ cxt->str_anchor = str;
+ cxt->rgn[FT_STRINGS].start = str;
+
+ /* fill in header fields */
+ p = (char *)bph;
+ bph->totalsize = cpu_to_be32(endp - p);
+ bph->off_mem_rsvmap = cpu_to_be32(cxt->rgn[FT_RSVMAP].start - p);
+ bph->off_dt_struct = cpu_to_be32(cxt->rgn[FT_STRUCT].start - p);
+ bph->off_dt_strings = cpu_to_be32(cxt->rgn[FT_STRINGS].start - p);
+ bph->dt_strings_size = cpu_to_be32(ssize);
+}
+
+void *ft_find_device(struct ft_cxt *cxt, const char *srch_path)
+{
+ char *node;
+
+ /* require absolute path */
+ if (srch_path[0] != '/')
+ return NULL;
+ node = ft_find_descendent(cxt, cxt->rgn[FT_STRUCT].start, srch_path);
+ return ft_node_add(cxt, node);
+}
+
+void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path)
+{
+ struct ft_atom atom;
+ char *p;
+ const char *cp, *q;
+ int cl;
+ int depth = -1;
+ int dmatch = 0;
+ const char *path_comp[FT_MAX_DEPTH];
+
+ cp = srch_path;
+ cl = 0;
+ p = top;
+
+ while ((p = ft_next(cxt, p, &atom)) != NULL) {
+ switch (atom.tag) {
+ case OF_DT_BEGIN_NODE:
+ ++depth;
+ if (depth != dmatch)
+ break;
+ cxt->genealogy[depth] = atom.data;
+ cxt->genealogy[depth + 1] = NULL;
+ if (depth && !(strncmp(atom.name, cp, cl) == 0
+ && (atom.name[cl] == '/'
+ || atom.name[cl] == '\0'
+ || atom.name[cl] == '@')))
+ break;
+ path_comp[dmatch] = cp;
+ /* it matches so far, advance to next path component */
+ cp += cl;
+ /* skip slashes */
+ while (*cp == '/')
+ ++cp;
+ /* we're done if this is the end of the string */
+ if (*cp == 0)
+ return atom.data;
+ /* look for end of this component */
+ q = strchr(cp, '/');
+ if (q)
+ cl = q - cp;
+ else
+ cl = strlen(cp);
+ ++dmatch;
+ break;
+ case OF_DT_END_NODE:
+ if (depth == 0)
+ return NULL;
+ if (dmatch > depth) {
+ --dmatch;
+ cl = cp - path_comp[dmatch] - 1;
+ cp = path_comp[dmatch];
+ while (cl > 0 && cp[cl - 1] == '/')
+ --cl;
+ }
+ --depth;
+ break;
+ }
+ }
+ return NULL;
+}
+
+void *ft_get_parent(struct ft_cxt *cxt, const void *phandle)
+{
+ void *node;
+ int d;
+ struct ft_atom atom;
+ char *p;
+
+ node = ft_node_ph2node(cxt, phandle);
+ if (node == NULL)
+ return NULL;
+
+ for (d = 0; cxt->genealogy[d] != NULL; ++d)
+ if (cxt->genealogy[d] == node)
+ return cxt->genealogy[d > 0 ? d - 1 : 0];
+
+ /* have to do it the hard way... */
+ p = cxt->rgn[FT_STRUCT].start;
+ d = 0;
+ while ((p = ft_next(cxt, p, &atom)) != NULL) {
+ switch (atom.tag) {
+ case OF_DT_BEGIN_NODE:
+ cxt->genealogy[d] = atom.data;
+ if (node == atom.data) {
+ /* found it */
+ cxt->genealogy[d + 1] = NULL;
+ return d > 0 ? cxt->genealogy[d - 1] : node;
+ }
+ ++d;
+ break;
+ case OF_DT_END_NODE:
+ --d;
+ break;
+ }
+ }
+ return NULL;
+}
+
+int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+ void *buf, const unsigned int buflen)
+{
+ struct ft_atom atom;
+ void *node;
+ char *p;
+ int depth;
+ unsigned int size;
+
+ node = ft_node_ph2node(cxt, phandle);
+ if (node == NULL)
+ return -1;
+
+ depth = 0;
+ p = (char *)node;
+
+ while ((p = ft_next(cxt, p, &atom)) != NULL) {
+ switch (atom.tag) {
+ case OF_DT_BEGIN_NODE:
+ ++depth;
+ break;
+ case OF_DT_PROP:
+ if ((depth != 1) || strcmp(atom.name, propname))
+ break;
+ size = min(atom.size, buflen);
+ memcpy(buf, atom.data, size);
+ return atom.size;
+ case OF_DT_END_NODE:
+ if (--depth <= 0)
+ return -1;
+ }
+ }
+ return -1;
+}
+
+int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+ const void *buf, const unsigned int buflen)
+{
+ struct ft_atom atom;
+ void *node;
+ char *p, *next;
+ int nextra, depth;
+
+ node = ft_node_ph2node(cxt, phandle);
+ if (node == NULL)
+ return -1;
+
+ depth = 0;
+ p = node;
+
+ while ((next = ft_next(cxt, p, &atom)) != NULL) {
+ switch (atom.tag) {
+ case OF_DT_BEGIN_NODE:
+ ++depth;
+ break;
+ case OF_DT_END_NODE:
+ if (--depth > 0)
+ break;
+ /* haven't found the property, insert here */
+ cxt->p = p;
+ return ft_prop(cxt, propname, buf, buflen);
+ case OF_DT_PROP:
+ if ((depth != 1) || strcmp(atom.name, propname))
+ break;
+ /* found an existing property, overwrite it */
+ nextra = _ALIGN(buflen, 4) - _ALIGN(atom.size, 4);
+ cxt->p = atom.data;
+ if (nextra && !ft_make_space(cxt, &cxt->p, FT_STRUCT,
+ nextra))
+ return -1;
+ *(u32 *) (cxt->p - 8) = cpu_to_be32(buflen);
+ ft_put_bin(cxt, buf, buflen);
+ return 0;
+ }
+ p = next;
+ }
+ return -1;
+}
+
+int ft_del_prop(struct ft_cxt *cxt, const void *phandle, const char *propname)
+{
+ struct ft_atom atom;
+ void *node;
+ char *p, *next;
+ int size;
+
+ node = ft_node_ph2node(cxt, phandle);
+ if (node == NULL)
+ return -1;
+
+ p = node;
+ while ((next = ft_next(cxt, p, &atom)) != NULL) {
+ switch (atom.tag) {
+ case OF_DT_BEGIN_NODE:
+ case OF_DT_END_NODE:
+ return -1;
+ case OF_DT_PROP:
+ if (strcmp(atom.name, propname))
+ break;
+ /* found the property, remove it */
+ size = 12 + -_ALIGN(atom.size, 4);
+ cxt->p = p;
+ if (!ft_make_space(cxt, &cxt->p, FT_STRUCT, -size))
+ return -1;
+ return 0;
+ }
+ p = next;
+ }
+ return -1;
+}
+
+void *ft_create_node(struct ft_cxt *cxt, const void *parent, const char *path)
+{
+ struct ft_atom atom;
+ char *p, *next;
+ int depth = 0;
+
+ p = cxt->rgn[FT_STRUCT].start;
+ while ((next = ft_next(cxt, p, &atom)) != NULL) {
+ switch (atom.tag) {
+ case OF_DT_BEGIN_NODE:
+ ++depth;
+ if (depth == 1 && strcmp(atom.name, path) == 0)
+ /* duplicate node path, return error */
+ return NULL;
+ break;
+ case OF_DT_END_NODE:
+ --depth;
+ if (depth > 0)
+ break;
+ /* end of node, insert here */
+ cxt->p = p;
+ ft_begin_node(cxt, path);
+ ft_end_node(cxt);
+ return p;
+ }
+ p = next;
+ }
+ return NULL;
+}
diff --git a/arch/powerpc/boot/flatdevtree.h b/arch/powerpc/boot/flatdevtree.h
index 761c8dc..b9cd9f6 100644
--- a/arch/powerpc/boot/flatdevtree.h
+++ b/arch/powerpc/boot/flatdevtree.h
@@ -17,7 +17,7 @@
#ifndef FLATDEVTREE_H
#define FLATDEVTREE_H
-#include "types.h"
+#include "flatdevtree_env.h"
/* Definitions used by the flattened device tree */
#define OF_DT_HEADER 0xd00dfeed /* marker */
@@ -43,4 +43,64 @@ struct boot_param_header {
u32 dt_strings_size; /* size of the DT strings block */
};
+struct ft_reserve {
+ u64 start;
+ u64 len;
+};
+
+struct ft_region {
+ char *start;
+ unsigned long size;
+};
+
+enum ft_rgn_id {
+ FT_RSVMAP,
+ FT_STRUCT,
+ FT_STRINGS,
+ FT_N_REGION
+};
+
+#define FT_MAX_DEPTH 50
+
+struct ft_cxt {
+ struct boot_param_header *bph;
+ int max_size; /* maximum size of tree */
+ int isordered; /* everything in standard order */
+ void *(*realloc)(void *, unsigned long);
+ char *str_anchor;
+ char *p; /* current insertion point in structs */
+ struct ft_region rgn[FT_N_REGION];
+ void *genealogy[FT_MAX_DEPTH+1];
+ char **node_tbl;
+ unsigned int node_max;
+ unsigned int nodes_used;
+};
+
+int ft_begin_node(struct ft_cxt *cxt, const char *name);
+void ft_end_node(struct ft_cxt *cxt);
+
+void ft_begin_tree(struct ft_cxt *cxt);
+void ft_end_tree(struct ft_cxt *cxt);
+
+void ft_nop(struct ft_cxt *cxt);
+int ft_prop(struct ft_cxt *cxt, const char *name,
+ const void *data, unsigned int sz);
+int ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str);
+int ft_prop_int(struct ft_cxt *cxt, const char *name, unsigned int val);
+void ft_begin(struct ft_cxt *cxt, void *blob, unsigned int max_size,
+ void *(*realloc_fn)(void *, unsigned long));
+int ft_open(struct ft_cxt *cxt, void *blob, unsigned int max_size,
+ unsigned int max_find_device,
+ void *(*realloc_fn)(void *, unsigned long));
+int ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size);
+
+void ft_dump_blob(const void *bphp);
+void ft_merge_blob(struct ft_cxt *cxt, void *blob);
+void *ft_find_device(struct ft_cxt *cxt, const char *srch_path);
+void *ft_find_descendent(struct ft_cxt *cxt, void *top, const char *srch_path);
+int ft_get_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+ void *buf, const unsigned int buflen);
+int ft_set_prop(struct ft_cxt *cxt, const void *phandle, const char *propname,
+ const void *buf, const unsigned int buflen);
+
#endif /* FLATDEVTREE_H */
diff --git a/arch/powerpc/boot/flatdevtree_env.h b/arch/powerpc/boot/flatdevtree_env.h
new file mode 100644
index 0000000..83bc1c7
--- /dev/null
+++ b/arch/powerpc/boot/flatdevtree_env.h
@@ -0,0 +1,47 @@
+/*
+ * This file adds the header file glue so that the shared files
+ * flatdevicetree.[ch] can compile and work in the powerpc bootwrapper.
+ *
+ * strncmp & strchr copied from <file:lib/strings.c>
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Maintained by: Mark A. Greer <mgreer@mvista.com>
+ */
+#ifndef _PPC_BOOT_FLATDEVTREE_ENV_H_
+#define _PPC_BOOT_FLATDEVTREE_ENV_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "string.h"
+#include "stdio.h"
+#include "ops.h"
+
+#define be16_to_cpu(x) (x)
+#define cpu_to_be16(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_be32(x) (x)
+#define be64_to_cpu(x) (x)
+#define cpu_to_be64(x) (x)
+
+static inline int strncmp(const char *cs, const char *ct, size_t count)
+{
+ signed char __res = 0;
+
+ while (count) {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ count--;
+ }
+ return __res;
+}
+
+static inline char *strchr(const char *s, int c)
+{
+ for (; *s != (char)c; ++s)
+ if (*s == '\0')
+ return NULL;
+ return (char *)s;
+}
+
+#endif /* _PPC_BOOT_FLATDEVTREE_ENV_H_ */
diff --git a/arch/powerpc/boot/flatdevtree_misc.c b/arch/powerpc/boot/flatdevtree_misc.c
new file mode 100644
index 0000000..c7f9adb
--- /dev/null
+++ b/arch/powerpc/boot/flatdevtree_misc.c
@@ -0,0 +1,56 @@
+/*
+ * This file does the necessary interface mapping between the bootwrapper
+ * device tree operations and the interface provided by shared source
+ * files flatdevicetree.[ch].
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * 2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <stddef.h>
+#include "flatdevtree.h"
+#include "ops.h"
+
+static struct ft_cxt cxt;
+
+static void *ft_finddevice(const char *name)
+{
+ return ft_find_device(&cxt, name);
+}
+
+static int ft_getprop(const void *phandle, const char *propname, void *buf,
+ const int buflen)
+{
+ return ft_get_prop(&cxt, phandle, propname, buf, buflen);
+}
+
+static int ft_setprop(const void *phandle, const char *propname,
+ const void *buf, const int buflen)
+{
+ return ft_set_prop(&cxt, phandle, propname, buf, buflen);
+}
+
+static void ft_pack(void)
+{
+ ft_end_tree(&cxt);
+}
+
+static unsigned long ft_addr(void)
+{
+ return (unsigned long)cxt.bph;
+}
+
+int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device)
+{
+ dt_ops.finddevice = ft_finddevice;
+ dt_ops.getprop = ft_getprop;
+ dt_ops.setprop = ft_setprop;
+ dt_ops.ft_pack = ft_pack;
+ dt_ops.ft_addr = ft_addr;
+
+ return ft_open(&cxt, dt_blob, max_size, max_find_device,
+ platform_ops.realloc);
+}
^ permalink raw reply related
* [PATCH 1/4] powerpc: More bootwrapper reorg
From: Mark A. Greer @ 2006-10-12 1:33 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
In-Reply-To: <20061012013223.GA9143@mag.az.mvista.com>
More reorganization of the bootwrapper:
- Add dtb section to zImage
- ft_init now called by platform_init
- Pack a flat dt before calling kernel
- Remove size parameter from free
- printf only calls console_ops.write it its not NULL
- Some cleanup
Signed-off-by: Mark A. Greer <mgreer@mvista.com>
---
main.c | 27 ++++++---------------------
of.c | 8 +-------
ops.h | 25 ++++++++++++++-----------
stdio.c | 3 ++-
wrapper | 4 ++--
zImage.lds.S | 5 +++++
6 files changed, 30 insertions(+), 42 deletions(-)
---
diff --git a/arch/powerpc/boot/main.c b/arch/powerpc/boot/main.c
index d719bb9..4184974 100644
--- a/arch/powerpc/boot/main.c
+++ b/arch/powerpc/boot/main.c
@@ -27,6 +27,8 @@ extern char _vmlinux_start[];
extern char _vmlinux_end[];
extern char _initrd_start[];
extern char _initrd_end[];
+extern char _dtb_start[];
+extern char _dtb_end[];
struct addr_range {
unsigned long addr;
@@ -250,10 +252,6 @@ #endif
flush_cache((void *)vmlinux.addr, vmlinux.size);
}
-void __attribute__ ((weak)) ft_init(void *dt_blob)
-{
-}
-
/* A buffer that may be edited by tools operating on a zImage binary so as to
* edit the command line passed to vmlinux (by setting /chosen/bootargs).
* The buffer is put in it's own section so that tools may locate it easier.
@@ -285,19 +283,12 @@ static void set_cmdline(char *buf)
setprop(devp, "bootargs", buf, strlen(buf) + 1);
}
-/* Section where ft can be tacked on after zImage is built */
-union blobspace {
- struct boot_param_header hdr;
- char space[8*1024];
-} dt_blob __attribute__((__section__("__builtin_ft")));
-
struct platform_ops platform_ops;
struct dt_ops dt_ops;
struct console_ops console_ops;
void start(unsigned long a1, unsigned long a2, void *promptr, void *sp)
{
- int have_dt = 0;
kernel_entry_t kentry;
char cmdline[COMMAND_LINE_SIZE];
@@ -306,15 +297,7 @@ void start(unsigned long a1, unsigned lo
memset(&dt_ops, 0, sizeof(dt_ops));
memset(&console_ops, 0, sizeof(console_ops));
- /* Override the dt_ops and device tree if there was an flat dev
- * tree attached to the zImage.
- */
- if (dt_blob.hdr.magic == OF_DT_HEADER) {
- have_dt = 1;
- ft_init(&dt_blob);
- }
-
- if (platform_init(promptr))
+ if (platform_init(promptr, _dtb_start, _dtb_end))
exit();
if (console_ops.open && (console_ops.open() < 0))
exit();
@@ -342,8 +325,10 @@ void start(unsigned long a1, unsigned lo
console_ops.close();
kentry = (kernel_entry_t) vmlinux.addr;
- if (have_dt)
+ if (_dtb_end > _dtb_start) {
+ dt_ops.ft_pack();
kentry(dt_ops.ft_addr(), 0, NULL);
+ }
else
/* XXX initrd addr/size should be passed in properties */
kentry(a1, a2, promptr);
diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c
index 3a71845..0182f38 100644
--- a/arch/powerpc/boot/of.c
+++ b/arch/powerpc/boot/of.c
@@ -256,24 +256,18 @@ static void of_console_write(char *buf,
call_prom("write", 3, 1, of_stdout_handle, buf, len);
}
-int platform_init(void *promptr)
+int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end)
{
- platform_ops.fixups = NULL;
platform_ops.image_hdr = of_image_hdr;
platform_ops.malloc = of_try_claim;
- platform_ops.free = NULL;
platform_ops.exit = of_exit;
dt_ops.finddevice = of_finddevice;
dt_ops.getprop = of_getprop;
dt_ops.setprop = of_setprop;
- dt_ops.translate_addr = NULL;
console_ops.open = of_console_open;
console_ops.write = of_console_write;
- console_ops.edit_cmdline = NULL;
- console_ops.close = NULL;
- console_ops.data = NULL;
prom = (int (*)(void *))promptr;
return 0;
diff --git a/arch/powerpc/boot/ops.h b/arch/powerpc/boot/ops.h
index 135eb4b..59832fb 100644
--- a/arch/powerpc/boot/ops.h
+++ b/arch/powerpc/boot/ops.h
@@ -22,7 +22,8 @@ struct platform_ops {
void (*fixups)(void);
void (*image_hdr)(const void *);
void * (*malloc)(u32 size);
- void (*free)(void *ptr, u32 size);
+ void (*free)(void *ptr);
+ void * (*realloc)(void *ptr, unsigned long size);
void (*exit)(void);
};
extern struct platform_ops platform_ops;
@@ -30,12 +31,11 @@ extern struct platform_ops platform_ops;
/* Device Tree operations */
struct dt_ops {
void * (*finddevice)(const char *name);
- int (*getprop)(const void *node, const char *name, void *buf,
+ int (*getprop)(const void *phandle, const char *name, void *buf,
const int buflen);
- int (*setprop)(const void *node, const char *name,
+ int (*setprop)(const void *phandle, const char *name,
const void *buf, const int buflen);
- u64 (*translate_addr)(const char *path, const u32 *in_addr,
- const u32 addr_len);
+ void (*ft_pack)(void);
unsigned long (*ft_addr)(void);
};
extern struct dt_ops dt_ops;
@@ -59,10 +59,13 @@ struct serial_console_data {
void (*close)(void);
};
-extern int platform_init(void *promptr);
-extern void simple_alloc_init(void);
-extern void ft_init(void *dt_blob);
-extern int serial_console_init(void);
+int platform_init(void *promptr, char *dt_blob_start, char *dt_blob_end);
+int ft_init(void *dt_blob, unsigned int max_size, unsigned int max_find_device);
+int serial_console_init(void);
+int ns16550_console_init(void *devp, struct serial_console_data *scdp);
+void *simple_alloc_init(char *base, u32 heap_size, u32 granularity,
+ u32 max_allocs);
+
static inline void *finddevice(const char *name)
{
@@ -84,10 +87,10 @@ static inline void *malloc(u32 size)
return (platform_ops.malloc) ? platform_ops.malloc(size) : NULL;
}
-static inline void free(void *ptr, u32 size)
+static inline void free(void *ptr)
{
if (platform_ops.free)
- platform_ops.free(ptr, size);
+ platform_ops.free(ptr);
}
static inline void exit(void)
diff --git a/arch/powerpc/boot/stdio.c b/arch/powerpc/boot/stdio.c
index 6d5f638..0a9feeb 100644
--- a/arch/powerpc/boot/stdio.c
+++ b/arch/powerpc/boot/stdio.c
@@ -320,6 +320,7 @@ printf(const char *fmt, ...)
va_start(args, fmt);
n = vsprintf(sprint_buf, fmt, args);
va_end(args);
- console_ops.write(sprint_buf, n);
+ if (console_ops.write)
+ console_ops.write(sprint_buf, n);
return n;
}
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index eab7318..b5fb1fe 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -179,11 +179,11 @@ if [ -z "$cacheit" ]; then
fi
if [ -n "$initrd" ]; then
- addsec $tmp "$initrd" initrd
+ addsec $tmp "$initrd" $isection
fi
if [ -n "$dtb" ]; then
- addsec $tmp "$dtb" dtb
+ addsec $tmp "$dtb" .kernel:dtb
fi
if [ "$platform" != "miboot" ]; then
diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S
index 4b6bb3f..4be3c64 100644
--- a/arch/powerpc/boot/zImage.lds.S
+++ b/arch/powerpc/boot/zImage.lds.S
@@ -21,6 +21,11 @@ SECTIONS
__got2_end = .;
}
+ . = ALIGN(8);
+ _dtb_start = .;
+ .kernel:dtb : { *(.kernel:dtb) }
+ _dtb_end = .;
+
. = ALIGN(4096);
_vmlinux_start = .;
.kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
^ permalink raw reply related
* [PATCH 0/4] powerpc: Next round of bootwrapper flat dt patches
From: Mark A. Greer @ 2006-10-12 1:32 UTC (permalink / raw)
To: Paul Mackerras; +Cc: linuxppc-dev
I'm resumitting the entire patch series because I messed up the
threading and made some changes to simple_alloc.
Mark
---
Hi,
This patch series is a respin of--and complete replacement for--the
bootwrapper reorg patches that I sent out a while back. I also included
the flatdevtree.c file which is the latest version that Paul sent plus
changes that I've made.
The patches apply to powerpc.git commit id:
ba00003aa83a61b615542dd66f5af8fb4a7cee1d
Paul, it would really help the rest of us if you would apply these patches
quickly. There are several people waiting for this work but there are so
many versions of so many patches that no one knows what to use. Plus, it
would get more people testing/debugging the flatdevtree code.
Summary of changes:
===================
more reorg patch
----------------
- This patch includes Paul's changes to zImage.lds.S which define
_dtb_start & _dtb_end and a related patch for the wrapper script.
- I changed main.c:start() a little so that the call to ft_init() is
done in platform_init(). I did this because of an interface change
to ft_init which now require some platform knowledge.
- I added a realloc() call to dt_ops so it can be passed to ft_open.
flatdevtree patch
-----------------
- I did not debug all of the flatdevtree.c code. I only debugged
ft_find_device, ft_get_prop, ft_set_prop and their supporting routines.
- I added a phandle table (insided the cxt) to track phandles returned by
ft_find_device(). Now the value returned by ft_find_device() is a phandle
which is nothing more than an index into the phandle table. The phandle
table contains the address of the corresponding node. When the flat dt
is edited/moved, the node pointers in the phandle table are updated
accordingly so no phandles kept by the caller become stale.
- I tested shrinking, and expanding an existing property but did not test
adding a new property.
- I'm not sure of the usefulness of the genealogy stuff but I left it there
in case Paul has plans for it. I did not test ft_get_parent (the only user
of genealogy).
simple_realloc patch
--------------------
- The flatdevtree code needs a realloc now so that is implemented in here.
- As the name implies, it is a simple allocator which uses a table to track
what's been allocated. simple_alloc_init() let's the caller set where
the heap is, its size, the granularity of its allocations, and how many
entries the table has.
- Once a slot in the table is used, its base & size are set. This allows
the code to be much simpler.
non-OF serial console patch
---------------------------
- I decided not to look for a /cpus/<some cpu>/64-bit property and instead
get either 1 or 2 "32-bit things" from the uart's 'virtual-reg' property.
If there is 1, its 32-bits; if its 2, its 64-bits.
Mark
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox