From patchwork Wed May 11 20:14:17 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Grant Likely X-Patchwork-Id: 1459 Return-Path: Delivered-To: unknown Received: from imap.gmail.com (74.125.159.109) by localhost6.localdomain6 with IMAP4-SSL; 08 Jun 2011 14:52:08 -0000 Delivered-To: patches@linaro.org Received: by 10.224.61.3 with SMTP id r3cs79868qah; Wed, 11 May 2011 13:14:22 -0700 (PDT) Received: by 10.223.33.80 with SMTP id g16mr2139787fad.125.1305144861544; Wed, 11 May 2011 13:14:21 -0700 (PDT) Received: from mail-fx0-f50.google.com (mail-fx0-f50.google.com [209.85.161.50]) by mx.google.com with ESMTPS id h7si921659fas.200.2011.05.11.13.14.21 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 11 May 2011 13:14:21 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.161.50 is neither permitted nor denied by best guess record for domain of grant.likely@secretlab.ca) client-ip=209.85.161.50; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.161.50 is neither permitted nor denied by best guess record for domain of grant.likely@secretlab.ca) smtp.mail=grant.likely@secretlab.ca Received: by mail-fx0-f50.google.com with SMTP id 16so811705fxm.37 for ; Wed, 11 May 2011 13:14:21 -0700 (PDT) Received: by 10.223.31.133 with SMTP id y5mr1610463fac.7.1305144861061; Wed, 11 May 2011 13:14:21 -0700 (PDT) Received: from angua (business-89-133-214-82.business.broadband.hu [89.133.214.82]) by mx.google.com with ESMTPS id r26sm207050fam.10.2011.05.11.13.14.18 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 11 May 2011 13:14:19 -0700 (PDT) Sender: Grant Likely Received: from localhost6.localdomain6 (angua [IPv6:::1]) by angua (Postfix) with ESMTP id A66DD3C0169; Wed, 11 May 2011 14:14:17 -0600 (MDT) Subject: [PATCH v6 4/5] arm/dt: probe for platforms via the device tree To: linaro-dev@lists.linaro.org, Thomas Gleixner , Russell King - ARM Linux , linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org From: Grant Likely Date: Wed, 11 May 2011 22:14:17 +0200 Message-ID: <20110511201417.21615.94279.stgit@localhost6.localdomain6> In-Reply-To: <20110511201401.21615.38893.stgit@localhost6.localdomain6> References: <20110511201401.21615.38893.stgit@localhost6.localdomain6> User-Agent: StGit/0.15 MIME-Version: 1.0 If a dtb is passed to the kernel then the kernel needs to iterate through compiled-in mdescs looking for one that matches and move the dtb data to a safe location before it gets accidentally overwritten by the kernel. This patch creates a new function, setup_machine_fdt() which is analogous to the setup_machine_atags() created in the previous patch. It does all the early setup needed to use a device tree machine description. v5: - Print warning with neither dtb nor atags are passed to the kernel - Fix bug in setting of __machine_arch_type to the selected machine, not just the last machine in the list. Reported-by: Tixy - Copy command line directly into boot_command_line instead of cmd_line v4: - Dump some output when a matching machine_desc cannot be found v3: - Added processing of reserved list. - Backed out the v2 change that copied instead of reserved the dtb. dtb is reserved again and the real problem was fixed by using alloc_bootmem_align() for early allocation of RAM for unflattening the tree. - Moved cmd_line and initrd changes to earlier patch to make series bisectable. v2: Changed to save the dtb by copying into an allocated buffer. - Since the dtb will very likely be passed in the first 16k of ram where the interrupt vectors live, memblock_reserve() is insufficient to protect the dtb data. [based on work originally written by Jeremy Kerr ] Tested-by: Tony Lindgren Signed-off-by: Grant Likely --- arch/arm/include/asm/mach/arch.h | 2 + arch/arm/include/asm/prom.h | 12 +++++ arch/arm/include/asm/setup.h | 2 + arch/arm/kernel/devtree.c | 98 ++++++++++++++++++++++++++++++++++++++ arch/arm/kernel/setup.c | 23 +++++++-- arch/arm/mm/init.c | 2 + 6 files changed, 135 insertions(+), 4 deletions(-) diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h index 4764e67..946f4d7 100644 --- a/arch/arm/include/asm/mach/arch.h +++ b/arch/arm/include/asm/mach/arch.h @@ -18,6 +18,8 @@ struct machine_desc { unsigned int nr; /* architecture number */ const char *name; /* architecture name */ unsigned long boot_params; /* tagged list */ + const char **dt_compat; /* array of device tree + * 'compatible' strings */ unsigned int nr_irqs; /* number of IRQs */ diff --git a/arch/arm/include/asm/prom.h b/arch/arm/include/asm/prom.h index 8f1037f..11b8708 100644 --- a/arch/arm/include/asm/prom.h +++ b/arch/arm/include/asm/prom.h @@ -21,5 +21,17 @@ static inline void irq_dispose_mapping(unsigned int virq) return; } +extern struct machine_desc *setup_machine_fdt(unsigned int dt_phys); +extern void arm_dt_memblock_reserve(void); + +#else /* CONFIG_OF */ + +static inline struct machine_desc *setup_machine_fdt(unsigned int dt_phys) +{ + return NULL; +} + +static inline void arm_dt_memblock_reserve(void) { } + #endif /* CONFIG_OF */ #endif /* ASMARM_PROM_H */ diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h index 93b4702..ee2ad8a 100644 --- a/arch/arm/include/asm/setup.h +++ b/arch/arm/include/asm/setup.h @@ -218,6 +218,8 @@ extern struct meminfo meminfo; #define bank_phys_size(bank) (bank)->size extern int arm_add_memory(phys_addr_t start, unsigned long size); +extern void early_print(const char *str, ...); +extern void dump_machine_table(void); #endif /* __KERNEL__ */ diff --git a/arch/arm/kernel/devtree.c b/arch/arm/kernel/devtree.c index 75e3df8..a701e42 100644 --- a/arch/arm/kernel/devtree.c +++ b/arch/arm/kernel/devtree.c @@ -21,6 +21,8 @@ #include #include +#include +#include void __init early_init_dt_add_memory_arch(u64 base, u64 size) { @@ -32,6 +34,102 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) return alloc_bootmem_align(size, align); } +void __init arm_dt_memblock_reserve(void) +{ + u64 *reserve_map, base, size; + + if (!initial_boot_params) + return; + + /* Reserve the dtb region */ + memblock_reserve(virt_to_phys(initial_boot_params), + be32_to_cpu(initial_boot_params->totalsize)); + + /* + * Process the reserve map. This will probably overlap the initrd + * and dtb locations which are already reserved, but overlaping + * doesn't hurt anything + */ + reserve_map = ((void*)initial_boot_params) + + be32_to_cpu(initial_boot_params->off_mem_rsvmap); + while (1) { + base = be64_to_cpup(reserve_map++); + size = be64_to_cpup(reserve_map++); + if (!size) + break; + memblock_reserve(base, size); + } +} + +/** + * setup_machine_fdt - Machine setup when an dtb was passed to the kernel + * @dt_phys: physical address of dt blob + * + * If a dtb was passed to the kernel in r2, then use it to choose the + * correct machine_desc and to setup the system. + */ +struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) +{ + struct boot_param_header *devtree; + struct machine_desc *mdesc, *mdesc_best = NULL; + unsigned int score, mdesc_score = ~1; + unsigned long dt_root; + const char *model; + + devtree = phys_to_virt(dt_phys); + + /* check device tree validity */ + if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) + return NULL; + + /* Search the mdescs for the 'best' compatible value match */ + initial_boot_params = devtree; + dt_root = of_get_flat_dt_root(); + for_each_machine_desc(mdesc) { + score = of_flat_dt_match(dt_root, mdesc->dt_compat); + if (score > 0 && score < mdesc_score) { + mdesc_best = mdesc; + mdesc_score = score; + } + } + if (!mdesc_best) { + const char *prop; + long size; + + early_print("\nError: unrecognized/unsupported " + "device tree compatible list:\n[ "); + + prop = of_get_flat_dt_prop(dt_root, "compatible", &size); + while (size > 0) { + early_print("'%s' ", prop); + size -= strlen(prop) + 1; + prop += strlen(prop) + 1; + } + early_print("]\n\n"); + + dump_machine_table(); /* does not return */ + } + + model = of_get_flat_dt_prop(dt_root, "model", NULL); + if (!model) + model = of_get_flat_dt_prop(dt_root, "compatible", NULL); + if (!model) + model = ""; + pr_info("Machine: %s, model: %s\n", mdesc_best->name, model); + + /* Retrieve various information from the /chosen node */ + of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); + /* Initialize {size,address}-cells info */ + of_scan_flat_dt(early_init_dt_scan_root, NULL); + /* Setup memory, calling early_init_dt_add_memory_arch */ + of_scan_flat_dt(early_init_dt_scan_memory, NULL); + + /* Change machine number to match the mdesc we're using */ + __machine_arch_type = mdesc_best->nr; + + return mdesc_best; +} + /** * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# * diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 42c2f0c..05db25e 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include #include +#include #include #include #include @@ -309,7 +311,7 @@ static void __init cacheid_init(void) */ extern struct proc_info_list *lookup_processor_type(unsigned int); -static void __init early_print(const char *str, ...) +void __init early_print(const char *str, ...) { extern void printascii(const char *); char buf[256]; @@ -439,7 +441,7 @@ void cpu_init(void) : "r14"); } -static void __init dump_machine_table(void) +void __init dump_machine_table(void) { struct machine_desc *p; @@ -837,8 +839,17 @@ static struct machine_desc * __init setup_machine_tags(unsigned int nr) if (tags->hdr.tag != ATAG_CORE) convert_to_tag_list(tags); #endif - if (tags->hdr.tag != ATAG_CORE) + + if (tags->hdr.tag != ATAG_CORE) { +#if defined(CONFIG_OF) + /* + * If CONFIG_OF is set, then assume this is a reasonably + * modern system that should pass boot parameters + */ + early_print("Warning: Neither atags nor dtb found\n"); +#endif tags = (struct tag *)&init_tags; + } if (mdesc->fixup) mdesc->fixup(mdesc, tags, &from, &meminfo); @@ -864,7 +875,9 @@ void __init setup_arch(char **cmdline_p) unwind_init(); setup_processor(); - mdesc = setup_machine_tags(machine_arch_type); + mdesc = setup_machine_fdt(__atags_pointer); + if (!mdesc) + mdesc = setup_machine_tags(machine_arch_type); machine_desc = mdesc; machine_name = mdesc->name; @@ -887,6 +900,8 @@ void __init setup_arch(char **cmdline_p) paging_init(mdesc); request_standard_resources(mdesc); + unflatten_device_tree(); + #ifdef CONFIG_SMP if (is_smp()) smp_init_cpus(); diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 26c4054..b265975 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -322,6 +323,7 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc) #endif arm_mm_memblock_reserve(); + arm_dt_memblock_reserve(); /* reserve any platform specific memblock areas */ if (mdesc->reserve)