Hello, This patch series is divided in 4 parts: - Patch 1-6: Minor bug fixes - Patch 7-10: Add hierarchical device tree support based on linux tree - Patch 11-24: Remove harcoded part - Patch 25-28: Arndale support based on Anthony''s git Xen can boot on both Arndale Board and the Versatile Express without recompilation. But there is still some hardcoded part, mainly in assembly. Things to do: - Move secondary CPUs bring up code in platform specific - Move out of Xen the switch between secure mode and hypervisor mode - Rework dom0 device tree creation - Use everywhere the new device tree API - Add a support for SYS MMU If you want to try this patch series you can clone: git clone -b arm git://xenbits.xen.org/people/julieng/xen-unstable.git The command line to compile Xen is the same as before. You just need to specify on Xen command line, via the device tree, which UART will be used for the console. Sincerely yours, Julien Grall (29): xen/arm: lr must be included in range [0-nr_lr[ xen/arm: don''t allow dom0 to access to vpl011 UART0 memory range xen/arm: Remove duplicated GICD_ICPIDR2 definition xen/arm: Bump early printk internal buffer to 512 xen/arm: Fix early_panic when EARLY_PRINTK is disabled xen/arm: Load dtb after dom0 kernel xen/arm: Create a hierarchical device tree xen/arm: Add helpers to use the device tree xen/arm: Add helpers to retrieve an address from the device tree xen/arm: Add helpers to retrieve an interrupt description from the device tree xen/arm: Introduce gic_route_dt_irq xen/arm: Introduce gic_irq_xlate xen/arm: Use hierarchical device tree to retrieve GIC information xen/arm: Retrieve timer interrupts from the device tree xen/arm: Don''t hardcode VGIC informations xen/arm: Introduce a generic way to use a device from the device tree xen/arm: New callback in uart_driver to get device tree interrupt structure xen/arm: add generic UART to get the device in the device tree xen/arm: Use device tree API in pl011 UART driver xen/arm: Use the device tree to map the address range and IRQ to dom0 xen/arm: WORKAROUND 1:1 memory mapping for dom0 xen/arm: Allow Xen to run on multiple platform without recompilation xen/arm: Add versatile express platform xen/arm: Don''t use pl011 UART by default for early printk xen/arm: Add exynos 4210 UART support xen/arm: Add Exynos 4210 UART support for early printk xen/arm: Add platform specific code for the exynos5 xen/arm: Support secondary cpus boot and switch to hypervisor for the exynos5 xen/arm64: Remove hardcoded value for gic in assembly code config/arm32.mk | 13 + config/arm64.mk | 11 + xen/arch/arm/Makefile | 4 +- xen/arch/arm/Rules.mk | 13 + xen/arch/arm/arm32/Makefile | 6 +- xen/arch/arm/arm32/debug-exynos5.S | 81 ++ xen/arch/arm/arm32/debug-pl011.S | 64 ++ xen/arch/arm/arm32/debug.S | 33 + xen/arch/arm/arm32/head.S | 85 +- xen/arch/arm/arm32/mode_switch.S | 74 +- xen/arch/arm/arm64/Makefile | 3 + xen/arch/arm/arm64/debug-pl011.S | 64 ++ xen/arch/arm/arm64/debug.S | 33 + xen/arch/arm/arm64/head.S | 69 +- xen/arch/arm/arm64/mode_switch.S | 7 +- xen/arch/arm/device.c | 74 ++ xen/arch/arm/domain_build.c | 202 ++++- xen/arch/arm/early_printk.c | 18 +- xen/arch/arm/gic.c | 154 +++- xen/arch/arm/kernel.h | 1 - xen/arch/arm/platform.c | 121 +++ xen/arch/arm/platforms/Makefile | 1 + xen/arch/arm/platforms/exynos5.c | 105 +++ xen/arch/arm/platforms/vexpress.c | 26 + xen/arch/arm/setup.c | 14 +- xen/arch/arm/shutdown.c | 16 +- xen/arch/arm/time.c | 65 +- xen/arch/arm/vgic.c | 21 +- xen/arch/arm/vpl011.c | 4 +- xen/arch/arm/xen.lds.S | 12 + xen/common/device_tree.c | 1319 ++++++++++++++++++++++++++++-- xen/drivers/char/Makefile | 2 + xen/drivers/char/arm-uart.c | 76 ++ xen/drivers/char/exynos5-uart.c | 346 ++++++++ xen/drivers/char/pl011.c | 63 +- xen/drivers/char/serial.c | 10 + xen/include/asm-arm/config.h | 13 +- xen/include/asm-arm/device.h | 52 ++ xen/include/asm-arm/domain.h | 5 +- xen/include/asm-arm/early_printk.h | 4 +- xen/include/asm-arm/gic.h | 16 +- xen/include/asm-arm/platform.h | 70 ++ xen/include/asm-arm/platforms/exynos5.h | 40 + xen/include/asm-arm/platforms/vexpress.h | 14 + xen/include/asm-arm/time.h | 3 + xen/include/xen/device_tree.h | 347 +++++++- xen/include/xen/irq.h | 25 + xen/include/xen/serial.h | 14 +- 48 files changed, 3508 insertions(+), 305 deletions(-) create mode 100644 xen/arch/arm/arm32/debug-exynos5.S create mode 100644 xen/arch/arm/arm32/debug-pl011.S create mode 100644 xen/arch/arm/arm32/debug.S create mode 100644 xen/arch/arm/arm64/debug-pl011.S create mode 100644 xen/arch/arm/arm64/debug.S create mode 100644 xen/arch/arm/device.c create mode 100644 xen/arch/arm/platform.c create mode 100644 xen/arch/arm/platforms/exynos5.c create mode 100644 xen/drivers/char/arm-uart.c create mode 100644 xen/drivers/char/exynos5-uart.c create mode 100644 xen/include/asm-arm/device.h create mode 100644 xen/include/asm-arm/platform.h create mode 100644 xen/include/asm-arm/platforms/exynos5.h -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 01/29] xen/arm: lr must be included in range [0-nr_lr[
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index bc8faf2..bac2af2 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -512,7 +512,9 @@ static inline void gic_set_lr(int lr, unsigned int virtual_irq, { int maintenance_int = GICH_LR_MAINTENANCE_IRQ; - BUG_ON(lr > nr_lrs); + BUG_ON(lr >= nr_lrs); + BUG_ON(lr < 0); + BUG_ON(state & ~(GICH_LR_STATE_MASK<<GICH_LR_STATE_SHIFT)); GICH[GICH_LR + lr] = state | maintenance_int | -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 02/29] xen/arm: don''t allow dom0 to access to vpl011 UART0 memory range
As vpl011 UART is not initialized for dom 0, when the domain tries to access to this range, a segfault will occur in Xen. The right behaviour should be a data abort for the guest. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/vpl011.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c index 9472d0a..13ba623 100644 --- a/xen/arch/arm/vpl011.c +++ b/xen/arch/arm/vpl011.c @@ -85,7 +85,9 @@ static void uart0_print_char(char c) static int uart0_mmio_check(struct vcpu *v, paddr_t addr) { - return addr >= UART0_START && addr < UART0_END; + struct domain *d = v->domain; + + return d->domain_id != 0 && addr >= UART0_START && addr < UART0_END; } static int uart0_mmio_read(struct vcpu *v, mmio_info_t *info) -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 03/29] xen/arm: Remove duplicated GICD_ICPIDR2 definition
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/include/asm-arm/gic.h | 1 - 1 file changed, 1 deletion(-) diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 47354dd..c3f87e1 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -43,7 +43,6 @@ #define GICD_ICFGRN (0xCFC/4) #define GICD_NSACR (0xE00/4) #define GICD_NSACRN (0xEFC/4) -#define GICD_ICPIDR2 (0xFE8/4) #define GICD_SGIR (0xF00/4) #define GICD_CPENDSGIR (0xF10/4) #define GICD_CPENDSGIRN (0xF1C/4) -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 04/29] xen/arm: Bump early printk internal buffer to 512
When debug is enabled in device tree code, some lines are bigger than 80 characters. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/early_printk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c index bdf4c0e..b21f572 100644 --- a/xen/arch/arm/early_printk.c +++ b/xen/arch/arm/early_printk.c @@ -41,7 +41,7 @@ static void __init early_puts(const char *s) static void __init early_vprintk(const char *fmt, va_list args) { - char buf[80]; + char buf[512]; vsnprintf(buf, sizeof(buf), fmt, args); early_puts(buf); -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 05/29] xen/arm: Fix early_panic when EARLY_PRINTK is disabled
Even if EARLY_PRINTK is not enabled, early_panic must never return. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/include/asm-arm/early_printk.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/include/asm-arm/early_printk.h b/xen/include/asm-arm/early_printk.h index a770d4a..a0297a7 100644 --- a/xen/include/asm-arm/early_printk.h +++ b/xen/include/asm-arm/early_printk.h @@ -20,7 +20,7 @@ void early_panic(const char *fmt, ...) __attribute__((noreturn)); #else static inline void early_printk(const char *fmt, ...) {} -static inline void early_panic(const char *fmt, ...) {} +static inline void __attribute__((noreturn)) early_panic(const char *fmt, ...) {while(1);} #endif -- Julien Grall
On some setup, the first linux page table is at 0x40004000. Xen will load dom0 device tree at 0x4000100. In case of the device tree is big, linux will corrupt the device tree. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/domain_build.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 3f50193..ad0ab35 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -407,8 +407,9 @@ int construct_dom0(struct domain *d) /* The following loads use the domain''s p2m */ p2m_load_VTTBR(d); - dtb_load(&kinfo); + kinfo.dtb_paddr = kinfo.zimage.load_addr + kinfo.zimage.len; kernel_load(&kinfo); + dtb_load(&kinfo); discard_initial_modules(); -- Julien Grall
Add function to parse the device tree and create a hierarchical tree. This code is based on drivers/of/base.c in linux source. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/setup.c | 5 + xen/common/device_tree.c | 452 ++++++++++++++++++++++++++++++++++++++++- xen/include/xen/device_tree.h | 98 +++++++++ 3 files changed, 551 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index cfe3d94..77d0879 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -428,12 +428,17 @@ void __init start_xen(unsigned long boot_phys_offset, setup_pagetables(boot_phys_offset, get_xen_paddr()); setup_mm(fdt_paddr, fdt_size); + dt_unflatten_host_device_tree(); + #ifdef EARLY_UART_ADDRESS /* TODO Need to get device tree or command line for UART address */ pl011_init(0, FIXMAP_ADDR(FIXMAP_CONSOLE)); console_init_preirq(); #endif + /* FIXME: Do something smarter */ + dt_switch_to_printk(); + processor_id(); init_xen_time(); diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 7997f41..05285b7 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -2,6 +2,8 @@ * Device Tree * * Copyright (C) 2012 Citrix Systems, Inc. + * Copyright 2009 Benjamin Herrenschmidt, IBM Corp + * benh@kernel.crashing.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -19,15 +21,51 @@ #include <xen/stdarg.h> #include <xen/string.h> #include <xen/cpumask.h> +#include <xen/ctype.h> +#include <xen/lib.h> #include <asm/early_printk.h> struct dt_early_info __initdata early_info; void *device_tree_flattened; +/* Host device tree */ +struct dt_device_node *dt_host; + +/** + * struct dt_alias_prop - Alias property in ''aliases'' node + * @link: List node to link the structure in aliases_lookup list + * @alias: Alias property name + * @np: Pointer to device_node that the alias stands for + * @id: Index value from end of alias name + * @stem: Alias string without the index + * + * The structure represents one alias property of ''aliases'' node as + * an entry in aliases_lookup list. + */ +struct dt_alias_prop { + struct list_head link; + const char *alias; + struct dt_device_node *np; + int id; + char stem[0]; +}; + +static LIST_HEAD(aliases_lookup); + /* Some device tree functions may be called both before and after the console is initialized. */ static void (*dt_printk)(const char *fmt, ...) = early_printk; +#define ALIGN(x, a) ((x + (a) - 1) & ~((a) - 1)); + +// #define DEBUG_DT + +#ifdef DEBUG_DT +# define dt_dprintk(fmt, args...) dt_printk(XENLOG_DEBUG fmt, ##args) +#else +# define dt_dprintk(fmt, args...) do {} while ( 0 ) +#endif + bool_t device_tree_node_matches(const void *fdt, int node, const char *match) { const char *name; @@ -263,7 +301,7 @@ static int dump_node(const void *fdt, int node, const char *name, int depth, if ( name[0] == ''\0'' ) name = "/"; - printk("%s%s:\n", prefix, name); + dt_printk("%s%s:\n", prefix, name); for ( prop = fdt_first_property_offset(fdt, node); prop >= 0; @@ -273,7 +311,7 @@ static int dump_node(const void *fdt, int node, const char *name, int depth, p = fdt_get_property_by_offset(fdt, prop, NULL); - printk("%s %s\n", prefix, fdt_string(fdt, fdt32_to_cpu(p->nameoff))); + dt_printk("%s %s\n", prefix, fdt_string(fdt, fdt32_to_cpu(p->nameoff))); } return 0; @@ -488,11 +526,417 @@ size_t __init device_tree_early_init(const void *fdt) device_tree_for_each_node((void *)fdt, early_scan_node, NULL); early_print_info(); - dt_printk = printk; - return fdt_totalsize(fdt); } +static void __init *unflatten_dt_alloc(unsigned long *mem, unsigned long size, + unsigned long align) +{ + void *res; + + *mem = ALIGN(*mem, align); + res = (void *)*mem; + *mem += size; + + return res; +} + +/* Find a property with a given name for a given node and return it. */ +static const struct dt_property * +dt_find_property(const struct dt_device_node *np, + const char *name, + u32 *lenp) +{ + const struct dt_property *pp; + + if ( !np ) + return NULL; + + for ( pp = np->properties; pp; pp = pp->next ) + { + if ( strcmp(pp->name, name) == 0 ) + { + if ( lenp ) + *lenp = pp->length; + break; + } + } + + return pp; +} + +const void *dt_get_property(const struct dt_device_node *np, + const char *name, u32 *lenp) +{ + const struct dt_property *pp = dt_find_property(np, name, lenp); + + return pp ? pp->value : NULL; +} + +struct dt_device_node *dt_find_node_by_path(const char *path) +{ + struct dt_device_node *np; + + for_each_device_node(dt_host, np) + if ( np->full_name && (dt_node_cmp(np->full_name, path) == 0) ) + break; + + return np; +} + +/** + * unflatten_dt_node - Alloc and populate a device_node from the flat tree + * @fdt: The parent device tree blob + * @mem: Memory chunk to use for allocating device nodes and properties + * @p: pointer to node in flat tree + * @dad: Parent struct device_node + * @allnextpp: pointer to ->allnext from last allocated device_node + * @fpsize: Size of the node path up at the current depth. + */ +static unsigned long __init unflatten_dt_node(const void *fdt, + unsigned long mem, + unsigned long *p, + struct dt_device_node *dad, + struct dt_device_node ***allnextpp, + unsigned long fpsize) +{ + struct dt_device_node *np; + struct dt_property *pp, **prev_pp = NULL; + char *pathp; + u32 tag; + unsigned int l, allocl; + int has_name = 0; + int new_format = 0; + + tag = be32_to_cpup((__be32 *)(*p)); + if ( tag != FDT_BEGIN_NODE ) + { + dt_printk(XENLOG_WARNING "Weird tag at start of node: %x\n", tag); + return mem; + } + *p += 4; + pathp = (char *)*p; + l = allocl = strlen(pathp) + 1; + *p = ALIGN(*p + l, 4); + + /* version 0x10 has a more compact unit name here instead of the full + * path. we accumulate the full path size using "fpsize", we''ll rebuild + * it later. We detect this because the first character of the name is + * not ''/''. + */ + if ( (*pathp) != ''/'' ) + { + new_format = 1; + if ( fpsize == 0 ) + { + /* root node: special case. fpsize accounts for path + * plus terminating zero. root node only has ''/'', so + * fpsize should be 2, but we want to avoid the first + * level nodes to have two ''/'' so we use fpsize 1 here + */ + fpsize = 1; + allocl = 2; + } + else + { + /* account for ''/'' and path size minus terminal 0 + * already in ''l'' + */ + fpsize += l; + allocl = fpsize; + } + } + + np = unflatten_dt_alloc(&mem, sizeof(struct dt_device_node) + allocl, + __alignof__(struct dt_device_node)); + if ( allnextpp ) + { + memset(np, 0, sizeof(*np)); + np->full_name = ((char *)np) + sizeof(struct dt_device_node); + /* By default dom0 owns the dom0 */ + np->used_by = 0; + if ( new_format ) + { + char *fn = np->full_name; + /* rebuild full path for new format */ + if ( dad && dad->parent ) + { + strlcpy(fn, dad->full_name, allocl); +#ifdef DEBUG_DT + if ( (strlen(fn) + l + 1) != allocl ) + { + dt_dprintk("%s: p: %d, l: %d, a: %d\n", + pathp, (int)strlen(fn), + l, allocl); + } +#endif + fn += strlen(fn); + } + *(fn++) = ''/''; + memcpy(fn, pathp, l); + } + else + memcpy(np->full_name, pathp, l); + prev_pp = &np->properties; + **allnextpp = np; + *allnextpp = &np->allnext; + if ( dad != NULL ) + { + np->parent = dad; + /* we temporarily use the next field as `last_child''*/ + if ( dad->next == NULL ) + dad->child = np; + else + dad->next->sibling = np; + dad->next = np; + } + } + /* process properties */ + while ( 1 ) + { + u32 sz, noff; + const char *pname; + + tag = be32_to_cpup((__be32 *)(*p)); + if ( tag == FDT_NOP ) + { + *p += 4; + continue; + } + if ( tag != FDT_PROP ) + break; + *p += 4; + sz = be32_to_cpup((__be32 *)(*p)); + noff = be32_to_cpup((__be32 *)((*p) + 4)); + *p += 8; + if ( fdt_version(fdt) < 0x10 ) + *p = ALIGN(*p, sz >= 8 ? 8 : 4); + + pname = fdt_string(fdt, noff); + if ( pname == NULL ) + { + dt_dprintk("Can''t find property name in list!\n"); + break; + } + if ( strcmp(pname, "name") == 0 ) + has_name = 1; + l = strlen(pname) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct dt_property), + __alignof__(struct dt_property)); + if ( allnextpp ) + { + /* We accept flattened tree phandles either in + * ePAPR-style "phandle" properties, or the + * legacy "linux,phandle" properties. If both + * appear and have different values, things + * will get weird. Don''t do that. */ + if ( (strcmp(pname, "phandle") == 0) || + (strcmp(pname, "linux,phandle") == 0) ) + { + if ( np->phandle == 0 ) + np->phandle = be32_to_cpup((__be32*)*p); + } + /* And we process the "ibm,phandle" property + * used in pSeries dynamic device tree + * stuff */ + if ( strcmp(pname, "ibm,phandle") == 0 ) + np->phandle = be32_to_cpup((__be32 *)*p); + pp->name = pname; + pp->length = sz; + pp->value = (void *)*p; + *prev_pp = pp; + prev_pp = &pp->next; + } + *p = ALIGN((*p) + sz, 4); + } + /* with version 0x10 we may not have the name property, recreate + * it here from the unit name if absent + */ + if ( !has_name ) + { + char *p1 = pathp, *ps = pathp, *pa = NULL; + int sz; + + while ( *p1 ) + { + if ( (*p1) == ''@'' ) + pa = p1; + if ( (*p1) == ''/'' ) + ps = p1 + 1; + p1++; + } + if ( pa < ps ) + pa = p1; + sz = (pa - ps) + 1; + pp = unflatten_dt_alloc(&mem, sizeof(struct dt_property) + sz, + __alignof__(struct dt_property)); + if ( allnextpp ) + { + pp->name = "name"; + pp->length = sz; + pp->value = pp + 1; + *prev_pp = pp; + prev_pp = &pp->next; + memcpy(pp->value, ps, sz - 1); + ((char *)pp->value)[sz - 1] = 0; + dt_dprintk("fixed up name for %s -> %s\n", pathp, + (char *)pp->value); + } + } + if ( allnextpp ) + { + *prev_pp = NULL; + np->name = dt_get_property(np, "name", NULL); + np->type = dt_get_property(np, "device_type", NULL); + + if ( !np->name ) + np->name = "<NULL>"; + if ( !np->type ) + np->type = "<NULL>"; + } + while ( tag == FDT_BEGIN_NODE || tag == FDT_NOP ) + { + if ( tag == FDT_NOP ) + *p += 4; + else + mem = unflatten_dt_node(fdt, mem, p, np, allnextpp, fpsize); + tag = be32_to_cpup((__be32 *)(*p)); + } + if ( tag != FDT_END_NODE ) + { + dt_printk(XENLOG_WARNING "Weird tag at end of node: %x\n", tag); + return mem; + } + + *p += 4; + return mem; +} + +/** + * __unflatten_device_tree - create tree of device_nodes from flat blob + * + * unflattens a device-tree, creating the + * tree of struct device_node. It also fills the "name" and "type" + * pointers of the nodes so the normal device-tree walking functions + * can be used. + * @fdt: The fdt to expand + * @mynodes: The device_node tree created by the call + */ +static void __init __unflatten_device_tree(const void *fdt, + struct dt_device_node **mynodes) +{ + unsigned long start, mem, size; + struct dt_device_node **allnextp = mynodes; + + dt_dprintk(" -> unflatten_device_tree()\n"); + + dt_dprintk("Unflattening device tree:\n"); + dt_dprintk("magic: %#08x\n", fdt_magic(fdt)); + dt_dprintk("size: %#08x\n", fdt_totalsize(fdt)); + dt_dprintk("version: %#08x\n", fdt_version(fdt)); + + /* First pass, scan for size */ + start = ((unsigned long)fdt) + fdt_off_dt_struct(fdt); + size = unflatten_dt_node(fdt, 0, &start, NULL, NULL, 0); + size = (size | 3) + 1; + + dt_dprintk(" size is %#lx allocating...\n", size); + + /* Allocate memory for the expanded device tree */ + mem = (unsigned long)_xmalloc (size + 4, __alignof__(struct dt_device_node)); + + ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); + + dt_dprintk(" unflattening %lx...\n", mem); + + /* Second pass, do actual unflattening */ + start = ((unsigned long)fdt) + fdt_off_dt_struct(fdt); + unflatten_dt_node(fdt, mem, &start, NULL, &allnextp, 0); + if ( be32_to_cpup((__be32 *)start) != FDT_END ) + dt_printk(XENLOG_WARNING "Weird tag at end of tree: %08x\n", + *((u32 *)start)); + if ( be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef ) + dt_printk(XENLOG_WARNING "End of tree marker overwritten: %08x\n", + be32_to_cpu(((__be32 *)mem)[size / 4])); + *allnextp = NULL; + + dt_dprintk(" <- unflatten_device_tree()\n"); +} + +static void dt_alias_add(struct dt_alias_prop *ap, + struct dt_device_node *np, + int id, const char *stem, int stem_len) +{ + ap->np = np; + ap->id = id; + strlcpy(ap->stem, stem, stem_len + 1); + list_add_tail(&ap->link, &aliases_lookup); + dt_dprintk("adding DT alias:%s: stem=%s id=%d node=%s\n", + ap->alias, ap->stem, ap->id, dt_node_full_name(np)); +} + +/** + * dt_alias_scan - Scan all properties of ''aliases'' node + * + * The function scans all the properties of ''aliases'' node and populate + * the the global lookup table with the properties. It returns the + * number of alias_prop found, or error code in error case. + */ +static void __init dt_alias_scan(void) +{ + const struct dt_property *pp; + const struct dt_device_node *aliases; + + aliases = dt_find_node_by_path("/aliases"); + if ( !aliases ) + return; + + for_each_property_of_node( aliases, pp ) + { + const char *start = pp->name; + const char *end = start + strlen(start); + struct dt_device_node *np; + struct dt_alias_prop *ap; + int id, len; + + /* Skip those we do not want to proceed */ + if ( !strcmp(pp->name, "name") || + !strcmp(pp->name, "phandle") || + !strcmp(pp->name, "linux,phandle") ) + continue; + + np = dt_find_node_by_path(pp->value); + if ( !np ) + continue; + + /* walk the alias backwards to extract the id and work out + * the ''stem'' string */ + while ( isdigit(*(end-1)) && end > start ) + end--; + len = end - start; + + id = simple_strtoll(end, NULL, 10); + + /* Allocate an alias_prop with enough space for the stem */ + ap = _xmalloc(sizeof(*ap) + len + 1, 4); + if ( !ap ) + continue; + ap->alias = start; + dt_alias_add(ap, np, id, start, len); + } +} + +void __init dt_unflatten_host_device_tree(void) +{ + __unflatten_device_tree(device_tree_flattened, &dt_host); + dt_alias_scan(); +} + +void __init dt_switch_to_printk(void) +{ + dt_printk = printk; +} + /* * Local variables: * mode: C diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 19bda98..850a9bd 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -10,6 +10,10 @@ #ifndef __XEN_DEVICE_TREE_H__ #define __XEN_DEVICE_TREE_H__ +#include <asm/byteorder.h> +#include <public/xen.h> +#include <xen/init.h> +#include <xen/string.h> #include <xen/types.h> #define DEVICE_TREE_MAX_DEPTH 16 @@ -52,6 +56,51 @@ struct dt_early_info { struct dt_module_info modules; }; +typedef u32 dt_phandle; + +/** + * dt_property - describe a property for a device + * @name: name of the property + * @length: size of the value + * @value: pointer to data contained in the property + * @next: pointer to the next property of a specific node + */ +struct dt_property { + const char *name; + u32 length; + void *value; + struct dt_property *next; +}; + +#define DT_USED_BY_XEN DOMID_INVALID + +/** + * dt_device_node - describe a node in the device tree + * @name: name of the node + * @type: type of the node (ie: memory, cpu, ...) + * @full_name: full name, it''s composed of all the ascendant name separate by / + * @used_by: who owns the node? (ie: xen, dom0...) + * @properties: list of properties for the node + * @child: pointer to the first child + * @sibling: pointer to the next sibling + * @allnext: pointer to the next in list of all nodes + */ +struct dt_device_node { + const char *name; + const char *type; + dt_phandle phandle; + char *full_name; + domid_t used_by; /* By default it''s used by dom0 */ + + struct dt_property *properties; + struct dt_device_node *parent; + struct dt_device_node *child; + struct dt_device_node *sibling; + struct dt_device_node *next; /* TODO: Remove it. Only use to know the last children */ + struct dt_device_node *allnext; + +}; + typedef int (*device_tree_node_func)(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, @@ -77,4 +126,53 @@ int device_tree_for_each_node(const void *fdt, const char *device_tree_bootargs(const void *fdt); void device_tree_dump(const void *fdt); +/** + * dt_unflatten_host_device_tree - Unflatten the host device tree + * + * Create a hierarchical device tree for the host DTB to be able + * to retrieve parents. + */ +void __init dt_unflatten_host_device_tree(void); + +/** + * Dump device tree message with printk + * TODO: Find another way to switch between early_printk and printk + * int the device tree code + */ +void __init dt_switch_to_printk(void); + +/** + * Host device tree + * DO NOT modify it! + */ +extern struct dt_device_node *dt_host; + +#define dt_node_cmp(s1, s2) strcmp((s1), (s2)) +#define dt_compat_cmp(s1, s2, l) strnicmp((s1), (s2), l) + +#define for_each_property_of_node(dn, pp) \ + for ( pp = dn->properties; pp != NULL; pp = pp->next ) + +#define for_each_device_node(dt, dn) \ + for ( dn = dt; dn != NULL; dn = dn->allnext ) + +static inline const char *dt_node_full_name(const struct dt_device_node *np) +{ + return (np && np->full_name) ? np->full_name : "<no-node>"; +} + +/** + * Find a property with a given name for a given node + * and return the value. + */ +const void *dt_get_property(const struct dt_device_node *np, + const char *name, u32 *lenp); + +/** + * dt_find_node_by_path - Find a node matching a full DT path + * @path: The full path to match + * + * Returns a node pointer. + */ +struct dt_device_node *dt_find_node_by_path(const char *path); #endif -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 08/29] xen/arm: Add helpers to use the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/common/device_tree.c | 120 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 120 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 05285b7..dd4b813 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -573,6 +573,54 @@ const void *dt_get_property(const struct dt_device_node *np, return pp ? pp->value : NULL; } +bool_t dt_device_is_compatible(const struct dt_device_node *device, + const char *compat) +{ + const char* cp; + u32 cplen, l; + + cp = dt_get_property(device, "compatible", &cplen); + if ( cp == NULL ) + return 0; + while ( cplen > 0 ) + { + if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 ) + return 1; + l = strlen(cp) + 1; + cp += l; + cplen -= l; + } + + return 0; +} + +bool_t dt_machine_is_compatible(const char *compat) +{ + const struct dt_device_node *root; + bool_t rc = 0; + + root = dt_find_node_by_path("/"); + if ( root ) + { + rc = dt_device_is_compatible(root, compat); + } + return rc; +} + +struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from, + const char *name) +{ + struct dt_device_node *np; + struct dt_device_node *dt; + + dt = from ? from->allnext : dt_host; + for_each_device_node(dt, np) + if ( np->name && (dt_node_cmp(np->name, name) == 0) ) + break; + + return np; +} + struct dt_device_node *dt_find_node_by_path(const char *path) { struct dt_device_node *np; @@ -584,6 +632,78 @@ struct dt_device_node *dt_find_node_by_path(const char *path) return np; } +struct dt_device_node *dt_find_node_by_alias(const char *alias) +{ + const struct dt_alias_prop *app; + + list_for_each_entry( app, &aliases_lookup, link ) + { + if ( !strcmp(app->alias, alias) ) + return app->np; + } + + return NULL; +} + +const struct dt_device_node *dt_get_parent(const struct dt_device_node *node) +{ + if ( !node ) + return NULL; + + return node->parent; +} + +struct dt_device_node * +dt_find_compatible_node(struct dt_device_node *from, + const char *type, + const char *compatible) +{ + struct dt_device_node *np; + struct dt_device_node *dt; + + dt = from ? from->allnext : dt_host; + for_each_device_node(dt, np) + { + if ( type + && !(np->type && (dt_node_cmp(np->type, type) == 0)) ) + continue; + if ( dt_device_is_compatible(np, compatible) ) + break; + } + + return np; +} + +int dt_n_addr_cells(const struct dt_device_node *np) +{ + const __be32 *ip; + + do { + if ( np->parent ) + np = np->parent; + ip = dt_get_property(np, "#address-cells", NULL); + if ( ip ) + return be32_to_cpup(ip); + } while ( np->parent ); + /* No #address-cells property for the root node */ + return DT_ROOT_NODE_ADDR_CELLS_DEFAULT; +} + +int dt_n_size_cells(const struct dt_device_node *np) +{ + const __be32 *ip; + + do { + if ( np->parent ) + np = np->parent; + ip = dt_get_property(np, "#size-cells", NULL); + if ( ip ) + return be32_to_cpup(ip); + } while ( np->parent ); + /* No #address-cells property for the root node */ + return DT_ROOT_NODE_SIZE_CELLS_DEFAULT; +} + /** * unflatten_dt_node - Alloc and populate a device_node from the flat tree * @fdt: The parent device tree blob diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 850a9bd..9637652 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -150,17 +150,72 @@ extern struct dt_device_node *dt_host; #define dt_node_cmp(s1, s2) strcmp((s1), (s2)) #define dt_compat_cmp(s1, s2, l) strnicmp((s1), (s2), l) +/* Default #address and #size cells */ +#define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 1 +#define DT_ROOT_NODE_SIZE_CELLS_DEFAULT 1 + #define for_each_property_of_node(dn, pp) \ for ( pp = dn->properties; pp != NULL; pp = pp->next ) #define for_each_device_node(dt, dn) \ for ( dn = dt; dn != NULL; dn = dn->allnext ) +/* Helper to read a big number; size is in cells (not bytes) */ +static inline u64 dt_read_number(const __be32 *cell, int size) +{ + u64 r = 0; + + while ( size-- ) + r = (r << 32) | be32_to_cpu(*(cell++)); + return r; +} + static inline const char *dt_node_full_name(const struct dt_device_node *np) { return (np && np->full_name) ? np->full_name : "<no-node>"; } +static inline const char *dt_node_name(const struct dt_device_node *np) +{ + return (np && np->name) ? np->name : "<no-node>"; +} + +static inline bool_t +dt_device_type_is_equal(const struct dt_device_node *device, + const char *type) +{ + return !dt_node_cmp(device->type, type); +} + +static inline void dt_device_set_used_by(struct dt_device_node *device, + domid_t used_by) +{ + /* TODO: children must inherit to the used_by thing */ + device->used_by = used_by; +} + +static inline domid_t dt_device_used_by(const struct dt_device_node *device) +{ + return device->used_by; +} + +/** + * dt_find_compatible_node - Find a node based on type and one of the + * tokens in its "compatible" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. + * @type: The type string to match "device_type" or NULL to ignore + * @compatible: The string to match to one of the tokens in the device + * "compatible" list. + * + * Returns a node pointer. + */ +struct dt_device_node *dt_find_compatible_node(struct dt_device_node *from, + const char *type, + const char *compatible); + /** * Find a property with a given name for a given node * and return the value. @@ -169,10 +224,75 @@ const void *dt_get_property(const struct dt_device_node *np, const char *name, u32 *lenp); /** + * Checks if the given "compat" string matches one of the strings in + * the device''s "compatible" property + */ +bool_t dt_device_is_compatible(const struct dt_device_node *device, + const char *compat); + +/** + * dt_machine_is_compatible - Test root of device tree for a given compatible value + * @compat: compatible string to look for in root node''s compatible property. + * + * Returns true if the root node has the given value in its + * compatible property. + */ +bool_t dt_machine_is_compatible(const char *compat); + +/** + * dt_find_node_by_name - Find a node by its "name" property + * @from: The node to start searching from or NULL, the node + * you pass will not be searched, only the next one + * will; typically, you pass what the previous call + * returned. of_node_put() will be called on it + * @name: The name string to match against + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. + */ +struct dt_device_node *dt_find_node_by_name(struct dt_device_node *node, + const char *name); + +/** + * df_find_node_by_alias - Find a node matching an alias + * @alias: The alias to match + * + * Returns a node pointer. + */ +struct dt_device_node *dt_find_node_by_alias(const char *alias); + +/** * dt_find_node_by_path - Find a node matching a full DT path * @path: The full path to match * * Returns a node pointer. */ struct dt_device_node *dt_find_node_by_path(const char *path); + +/** + * dt_get_parent - Get a node''s parent if any + * @node: Node to get parent + * + * Returns a node pointer. + */ +const struct dt_device_node *dt_get_parent(const struct dt_device_node *node); + +/** + * dt_n_size_cells - Helper to retrieve the number of cell for the size + * @np: node to get the value + * + * This function retrieves for a give device-tree node the number of + * cell for the size field. + */ +int dt_n_size_cells(const struct dt_device_node *np); + +/** + * dt_n_addr_cells - Helper to retrieve the number of cell for the address + * @np: node to get the value + * + * This function retrieves for a give device-tree node the number of + * cell for the address field. + */ +int dt_n_addr_cells(const struct dt_device_node *np); + #endif -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 09/29] xen/arm: Add helpers to retrieve an address from the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/common/device_tree.c | 343 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 22 +++ 2 files changed, 365 insertions(+) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index dd4b813..001188a 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -62,10 +62,38 @@ static void (*dt_printk)(const char *fmt, ...) = early_printk; #ifdef DEBUG_DT # define dt_dprintk(fmt, args...) dt_printk(XENLOG_DEBUG fmt, ##args) +static void dt_dump_addr(const char *s, const __be32 *addr, int na) +{ + dt_dprintk("%s", s); + while ( na-- ) + dt_dprintk(" %08x", be32_to_cpu(*(addr++))); + dt_dprintk("\n"); +} #else # define dt_dprintk(fmt, args...) do {} while ( 0 ) +static void dt_dump_addr(const char *s, const __be32 *addr, int na) { } #endif +#define DT_BAD_ADDR ((u64)-1) + +/* Max address size we deal with */ +#define DT_MAX_ADDR_CELLS 4 +#define DT_CHECK_ADDR_COUNT(na) ((na) > 0 && (na) <= DT_MAX_ADDR_CELLS) +#define DT_CHECK_COUNTS(na, ns) (DT_CHECK_ADDR_COUNT(na) && (ns) > 0) + +/* Callbacks for bus specific translators */ +struct dt_bus +{ + const char *name; + const char *addresses; + int (*match)(const struct dt_device_node *parent); + void (*count_cells)(const struct dt_device_node *child, + int *addrc, int *sizec); + u64 (*map)(__be32 *addr, const __be32 *range, int na, int ns, int pna); + int (*translate)(__be32 *addr, u64 offset, int na); + unsigned int (*get_flags)(const __be32 *addr); +}; + bool_t device_tree_node_matches(const void *fdt, int node, const char *match) { const char *name; @@ -704,6 +732,321 @@ int dt_n_size_cells(const struct dt_device_node *np) return DT_ROOT_NODE_SIZE_CELLS_DEFAULT; } +/* + * Default translator (generic bus) + */ +static void dt_bus_default_count_cells(const struct dt_device_node *dev, + int *addrc, int *sizec) +{ + if ( addrc ) + *addrc = dt_n_addr_cells(dev); + if ( sizec ) + *sizec = dt_n_size_cells(dev); +} + +static u64 dt_bus_default_map(__be32 *addr, const __be32 *range, + int na, int ns, int pna) +{ + u64 cp, s, da; + + cp = dt_read_number(range, na); + s = dt_read_number(range + na + pna, ns); + da = dt_read_number(addr, na); + + dt_dprintk("DT: default map, cp=%llx, s=%llx, da=%llx\n", + (unsigned long long)cp, (unsigned long long)s, + (unsigned long long)da); + + /* + * If the number of address cells is larger than 2 we assume the + * mapping doesn''t specify a physical address. Rather, the address + * specifies an identifier that must match exactly. + */ + if ( na > 2 && memcmp(range, addr, na * 4) != 0 ) + return DT_BAD_ADDR; + + if ( da < cp || da >= (cp + s) ) + return DT_BAD_ADDR; + return da - cp; +} + +static int dt_bus_default_translate(__be32 *addr, u64 offset, int na) +{ + u64 a = dt_read_number(addr, na); + + memset(addr, 0, na * 4); + a += offset; + if ( na > 1 ) + addr[na - 2] = cpu_to_be32(a >> 32); + addr[na - 1] = cpu_to_be32(a & 0xffffffffu); + + return 0; +} +static unsigned int dt_bus_default_get_flags(const __be32 *addr) +{ + /* TODO: Return the type of memory (device, ...) for caching + * attribute during mapping */ + return 0; +} + +/* + * Array of bus specific translators + */ +static const struct dt_bus dt_busses[] +{ + /* Default */ + { + .name = "default", + .addresses = "reg", + .match = NULL, + .count_cells = dt_bus_default_count_cells, + .map = dt_bus_default_map, + .translate = dt_bus_default_translate, + .get_flags = dt_bus_default_get_flags, + }, +}; + +static const struct dt_bus *dt_match_bus(const struct dt_device_node *np) +{ + int i; + + for ( i = 0; i < ARRAY_SIZE(dt_busses); i++ ) + if ( !dt_busses[i].match || dt_busses[i].match(np) ) + return &dt_busses[i]; + BUG(); + + return NULL; +} + +static const __be32 *dt_get_address(const struct dt_device_node *dev, + int index, u64 *size, + unsigned int *flags) +{ + const __be32 *prop; + u32 psize; + const struct dt_device_node *parent; + const struct dt_bus *bus; + int onesize, i, na, ns; + + /* Get parent & match bus type */ + parent = dt_get_parent(dev); + if ( parent == NULL ) + return NULL; + bus = dt_match_bus(parent); + bus->count_cells(dev, &na, &ns); + + if ( !DT_CHECK_ADDR_COUNT(na) ) + return NULL; + + /* Get "reg" or "assigned-addresses" property */ + prop = dt_get_property(dev, bus->addresses, &psize); + if ( prop == NULL ) + return NULL; + psize /= 4; + + onesize = na + ns; + for ( i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++ ) + { + if ( i == index ) + { + if ( size ) + *size = dt_read_number(prop + na, ns); + if ( flags ) + *flags = bus->get_flags(prop); + return prop; + } + } + return NULL; +} + +static int dt_translate_one(const struct dt_device_node *parent, + const struct dt_bus *bus, + const struct dt_bus *pbus, + __be32 *addr, int na, int ns, + int pna, const char *rprop) +{ + const __be32 *ranges; + unsigned int rlen; + int rone; + u64 offset = DT_BAD_ADDR; + + ranges = dt_get_property(parent, rprop, &rlen); + if ( ranges == NULL ) + { + dt_printk(XENLOG_ERR "DT: no ranges; cannot translate\n"); + return 1; + } + if ( ranges == NULL || rlen == 0 ) + { + offset = dt_read_number(addr, na); + memset(addr, 0, pna * 4); + dt_dprintk("DT: empty ranges; 1:1 translation\n"); + goto finish; + } + + dt_dprintk("DT: walking ranges...\n"); + + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for ( ; rlen >= rone; rlen -= rone, ranges += rone ) + { + offset = bus->map(addr, ranges, na, ns, pna); + if ( offset != DT_BAD_ADDR ) + break; + } + if ( offset == DT_BAD_ADDR ) + { + dt_dprintk("DT: not found !\n"); + return 1; + } + memcpy(addr, ranges + na, 4 * pna); + +finish: + dt_dump_addr("DT: parent translation for:", addr, pna); + dt_dprintk("DT: with offset: %llx\n", (unsigned long long)offset); + + /* Translate it into parent bus space */ + return pbus->translate(addr, offset, pna); +} + +/* + * Translate an address from the device-tree into a CPU physical address, + * this walks up the tree and applies the various bus mappings on the + * way. + * + * Note: We consider that crossing any level with #size-cells == 0 to mean + * that translation is impossible (that is we are not dealing with a value + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + */ +static u64 __dt_translate_address(const struct dt_device_node *dev, + const __be32 *in_addr, const char *rprop) +{ + const struct dt_device_node *parent = NULL; + const struct dt_bus *bus, *pbus; + __be32 addr[DT_MAX_ADDR_CELLS]; + int na, ns, pna, pns; + u64 result = DT_BAD_ADDR; + + dt_dprintk("DT: ** translation for device %s **\n", dev->full_name); + + /* Get parent & match bus type */ + parent = dt_get_parent(dev); + if ( parent == NULL ) + goto bail; + bus = dt_match_bus(parent); + + /* Count address cells & copy address locally */ + bus->count_cells(dev, &na, &ns); + if ( !DT_CHECK_COUNTS(na, ns) ) + { + dt_printk(XENLOG_ERR "dt_parse: Bad cell count for %s\n", + dev->full_name); + goto bail; + } + memcpy(addr, in_addr, na * 4); + + dt_dprintk("DT: bus is %s (na=%d, ns=%d) on %s\n", + bus->name, na, ns, parent->full_name); + dt_dump_addr("DT: translating address:", addr, na); + + /* Translate */ + for ( ;; ) + { + /* Switch to parent bus */ + dev = parent; + parent = dt_get_parent(dev); + + /* If root, we have finished */ + if ( parent == NULL ) + { + dt_dprintk("DT: reached root node\n"); + result = dt_read_number(addr, na); + break; + } + + /* Get new parent bus and counts */ + pbus = dt_match_bus(parent); + pbus->count_cells(dev, &pna, &pns); + if ( !DT_CHECK_COUNTS(pna, pns) ) + { + printk(XENLOG_ERR "dt_parse: Bad cell count for %s\n", + dev->full_name); + break; + } + + dt_dprintk("DT: parent bus is %s (na=%d, ns=%d) on %s\n", + pbus->name, pna, pns, parent->full_name); + + /* Apply bus translation */ + if ( dt_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop) ) + break; + + /* Complete the move up one level */ + na = pna; + ns = pns; + bus = pbus; + + dt_dump_addr("DT: one level translation:", addr, na); + } + +bail: + return result; +} + +/* dt_device_address - Translate device tree address and return it */ +int dt_device_get_address(const struct dt_device_node *dev, int index, + u64 *addr, u64 *size) +{ + const __be32 *addrp; + unsigned int flags; + + addrp = dt_get_address(dev, index, size, &flags); + if ( addrp == NULL ) + return -EINVAL; + + if ( !addr ) + return -EINVAL; + + *addr = __dt_translate_address(dev, addrp, "ranges"); + + if ( *addr == DT_BAD_ADDR ) + return -EINVAL; + + return 0; +} + +unsigned int dt_number_of_address(const struct dt_device_node *dev) +{ + const __be32 *prop; + u32 psize; + const struct dt_device_node *parent; + const struct dt_bus *bus; + int onesize, na, ns; + + /* Get parent & match bus type */ + parent = dt_get_parent(dev); + if ( parent == NULL ) + return 0; + + bus = dt_match_bus(parent); + bus->count_cells(dev, &na, &ns); + + if ( !DT_CHECK_COUNTS(na, ns) ) + return 0; + + /* Get "reg" or "assigned-addresses" property */ + prop = dt_get_property(dev, bus->addresses, &psize); + if ( prop == NULL ) + return 0; + + psize /= 4; + onesize = na + ns; + + return (psize / onesize); +} + /** * unflatten_dt_node - Alloc and populate a device_node from the flat tree * @fdt: The parent device tree blob diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 9637652..020a3d0 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -278,6 +278,28 @@ struct dt_device_node *dt_find_node_by_path(const char *path); const struct dt_device_node *dt_get_parent(const struct dt_device_node *node); /** + * dt_device_get_address - Resolve an address for a device + * @device: the device whose address is to be resolved + * @index: index of the addres to resolve + * @addr: address filled by this function + * @size: size filled by this function + * + * This function resolves an address, walking the tree, for a give + * device-tree node. It returns 0 on success. + */ +int dt_device_get_address(const struct dt_device_node *dev, int index, + u64 *addr, u64 *size); + +/** + * dt_number_of_address - Get the number of addresse for a device + * @device: the device whose number of address is to be retrieved + * + * Return the number of address for this device or 0 if there is no + * address or an error occured/ + */ +unsigned int dt_number_of_address(const struct dt_device_node *device); + +/** * dt_n_size_cells - Helper to retrieve the number of cell for the size * @np: node to get the value * -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 10/29] xen/arm: Add helpers to retrieve an interrupt description from the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/common/device_tree.c | 362 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 99 +++++++++++ xen/include/xen/irq.h | 25 +++ 3 files changed, 486 insertions(+) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 001188a..c623fe2 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -27,8 +27,11 @@ struct dt_early_info __initdata early_info; void *device_tree_flattened; +dt_irq_xlate_func dt_irq_xlate; /* Host device tree */ struct dt_device_node *dt_host; +/* Interrupt controller node*/ +const struct dt_device_node *dt_interrupt_controller; /** * struct dt_alias_prop - Alias property in ''aliases'' node @@ -1017,6 +1020,81 @@ int dt_device_get_address(const struct dt_device_node *dev, int index, return 0; } +/** + * dt_find_node_by_phandle - Find a node given a phandle + * @handle: phandle of the node to find + * + * Returns a node pointer. + */ +static const struct dt_device_node *dt_find_node_by_phandle(dt_phandle handle) +{ + const struct dt_device_node *np; + + for_each_device_node(dt_host, np) + if ( np->phandle == handle ) + break; + + return np; +} + +/** + * dt_irq_find_parent - Given a device node, find its interrupt parent node + * @child: pointer to device node + * + * Returns a pointer to the interrupt parent node, or NULL if the interrupt + * parent could not be determined. + */ +static const struct dt_device_node * +dt_irq_find_parent(const struct dt_device_node *child) +{ + const struct dt_device_node *p; + const __be32 *parp; + + do + { + parp = dt_get_property(child, "interrupt-parent", NULL); + if ( parp == NULL ) + p = dt_get_parent(child); + else + p = dt_find_node_by_phandle(be32_to_cpup(parp)); + child = p; + } while ( p && dt_get_property(p, "#interrupt-cells", NULL) == NULL ); + + return p; +} + +unsigned int dt_number_of_irq(const struct dt_device_node *device) +{ + const struct dt_device_node *p; + const __be32 *intspec, *tmp; + u32 intsize, intlen; + + dt_dprintk("dt_irq_number: dev=%s\n", device->full_name); + + /* Get the interrupts property */ + intspec = dt_get_property(device, "interrupts", &intlen); + if ( intspec == NULL ) + return 0; + intlen /= sizeof(*intspec); + + dt_dprintk(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); + + /* Look for the interrupt parent. */ + p = dt_irq_find_parent(device); + if ( p == NULL ) + return 0; + + /* Get size of interrupt specifier */ + tmp = dt_get_property(p, "#interrupt-cells", NULL); + if ( tmp == NULL ) + return 0; + intsize = be32_to_cpu(*tmp); + + dt_dprintk(" intsize=%d intlen=%d\n", intsize, intlen); + + return (intlen / intsize); +} + unsigned int dt_number_of_address(const struct dt_device_node *dev) { const __be32 *prop; @@ -1048,6 +1126,274 @@ unsigned int dt_number_of_address(const struct dt_device_node *dev) } /** + * dt_irq_map_raw - Low level interrupt tree parsing + * @parent: the device interrupt parent + * @intspec: interrupt specifier ("interrupts" property of the device) + * @ointsize: size of the passed in interrupt specifier + * @addr: address specifier (start of "reg" property of the device) + * @oirq: structure dt_raw_irq filled by this function + * + * Returns 0 on success and a negative number on error + * + * This function is a low-level interrupt tree walking function. It + * can be used to do a partial walk with synthetized reg and interrupts + * properties, for example when resolving PCI interrupts when no device + * node exist for the parent. + */ +static int dt_irq_map_raw(const struct dt_device_node *parent, + const __be32 *intspec, u32 ointsize, + const __be32 *addr, + struct dt_raw_irq *oirq) +{ + const struct dt_device_node *ipar, *tnode, *old = NULL, *newpar = NULL; + const __be32 *tmp, *imap, *imask; + u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0; + u32 imaplen; + int match, i; + + dt_dprintk("dt_irq_map_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n", + parent->full_name, be32_to_cpup(intspec), + be32_to_cpup(intspec + 1), ointsize); + + ipar = parent; + + /* First get the #interrupt-cells property of the current cursor + * that tells us how to interpret the passed-in intspec. If there + * is none, we are nice and just walk up the tree + */ + do { + tmp = dt_get_property(ipar, "#interrupt-cells", NULL); + if ( tmp != NULL ) + { + intsize = be32_to_cpu(*tmp); + break; + } + tnode = ipar; + ipar = dt_irq_find_parent(ipar); + } while ( ipar ); + if ( ipar == NULL ) + { + dt_dprintk(" -> no parent found !\n"); + goto fail; + } + + dt_dprintk("dt_irq_map_raw: ipar=%s, size=%d\n", ipar->full_name, intsize); + + if ( ointsize != intsize ) + return -EINVAL; + + /* Look for this #address-cells. We have to implement the old linux + * trick of looking for the parent here as some device-trees rely on it + */ + old = ipar; + do { + tmp = dt_get_property(old, "#address-cells", NULL); + tnode = dt_get_parent(old); + old = tnode; + } while ( old && tmp == NULL ); + + old = NULL; + addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp); + + dt_dprintk(" -> addrsize=%d\n", addrsize); + + /* Now start the actual "proper" walk of the interrupt tree */ + while ( ipar != NULL ) + { + /* Now check if cursor is an interrupt-controller and if it is + * then we are done + */ + if ( dt_get_property(ipar, "interrupt-controller", NULL) != NULL ) + { + dt_dprintk(" -> got it !\n"); + if ( intsize > DT_MAX_IRQ_SPEC ) + { + dt_dprintk(" -> intsize(%u) greater than DT_MAX_IRQ_SPEC(%u)\n", + intsize, DT_MAX_IRQ_SPEC); + goto fail; + } + for ( i = 0; i < intsize; i++ ) + oirq->specifier[i] = dt_read_number(intspec + i, 1); + oirq->size = intsize; + oirq->controller = ipar; + return 0; + } + + /* Now look for an interrupt-map */ + imap = dt_get_property(ipar, "interrupt-map", &imaplen); + /* No interrupt map, check for an interrupt parent */ + if ( imap == NULL ) + { + dt_dprintk(" -> no map, getting parent\n"); + newpar = dt_irq_find_parent(ipar); + goto skiplevel; + } + imaplen /= sizeof(u32); + + /* Look for a mask */ + imask = dt_get_property(ipar, "interrupt-map-mask", NULL); + + /* If we were passed no "reg" property and we attempt to parse + * an interrupt-map, then #address-cells must be 0. + * Fail if it''s not. + */ + if ( addr == NULL && addrsize != 0 ) + { + dt_dprintk(" -> no reg passed in when needed !\n"); + goto fail; + } + + /* Parse interrupt-map */ + match = 0; + while ( imaplen > (addrsize + intsize + 1) && !match ) + { + /* Compare specifiers */ + match = 1; + for ( i = 0; i < addrsize && match; ++i ) + { + __be32 mask = imask ? imask[i] : cpu_to_be32(0xffffffffu); + match = ((addr[i] ^ imap[i]) & mask) == 0; + } + for ( ; i < (addrsize + intsize) && match; ++i ) + { + __be32 mask = imask ? imask[i] : cpu_to_be32(0xffffffffu); + match = ((intspec[i-addrsize] ^ imap[i]) & mask) == 0; + } + imap += addrsize + intsize; + imaplen -= addrsize + intsize; + + dt_dprintk(" -> match=%d (imaplen=%d)\n", match, imaplen); + + /* Get the interrupt parent */ + newpar = dt_find_node_by_phandle(be32_to_cpup(imap)); + imap++; + --imaplen; + + /* Check if not found */ + if ( newpar == NULL ) + { + dt_dprintk(" -> imap parent not found !\n"); + goto fail; + } + + /* Get #interrupt-cells and #address-cells of new + * parent + */ + tmp = dt_get_property(newpar, "#interrupt-cells", NULL); + if ( tmp == NULL ) + { + dt_dprintk(" -> parent lacks #interrupt-cells!\n"); + goto fail; + } + newintsize = be32_to_cpu(*tmp); + tmp = dt_get_property(newpar, "#address-cells", NULL); + newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp); + + dt_dprintk(" -> newintsize=%d, newaddrsize=%d\n", + newintsize, newaddrsize); + + /* Check for malformed properties */ + if ( imaplen < (newaddrsize + newintsize) ) + goto fail; + + imap += newaddrsize + newintsize; + imaplen -= newaddrsize + newintsize; + + dt_dprintk(" -> imaplen=%d\n", imaplen); + } + if ( !match ) + goto fail; + + old = newpar; + addrsize = newaddrsize; + intsize = newintsize; + intspec = imap - intsize; + addr = intspec - addrsize; + + skiplevel: + /* Iterate again with new parent */ + dt_dprintk(" -> new parent: %s\n", dt_node_full_name(newpar)); + ipar = newpar; + newpar = NULL; + } +fail: + return -EINVAL; +} + +int dt_device_get_raw_irq(const struct dt_device_node *device, int index, + struct dt_raw_irq *out_irq) +{ + const struct dt_device_node *p; + const __be32 *intspec, *tmp, *addr; + u32 intsize, intlen; + int res = -EINVAL; + + dt_dprintk("dt_device_get_raw_irq: dev=%s, index=%d\n", + device->full_name, index); + + /* Get the interrupts property */ + intspec = dt_get_property(device, "interrupts", &intlen); + if ( intspec == NULL ) + return -EINVAL; + intlen /= sizeof(*intspec); + + dt_dprintk(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen); + + /* Get the reg property (if any) */ + addr = dt_get_property(device, "reg", NULL); + + /* Look for the interrupt parent. */ + p = dt_irq_find_parent(device); + if ( p == NULL ) + return -EINVAL; + + /* Get size of interrupt specifier */ + tmp = dt_get_property(p, "#interrupt-cells", NULL); + if ( tmp == NULL ) + goto out; + intsize = be32_to_cpu(*tmp); + + dt_dprintk(" intsize=%d intlen=%d\n", intsize, intlen); + + /* Check index */ + if ( (index + 1) * intsize > intlen ) + goto out; + + /* Get new specifier and map it */ + res = dt_irq_map_raw(p, intspec + index * intsize, intsize, + addr, out_irq); + if ( res ) + goto out; +out: + return res; +} + +int dt_irq_translate(const struct dt_raw_irq *raw, + struct dt_irq *out_irq) +{ + ASSERT(dt_irq_xlate != NULL); + + /* TODO: Retrieve the right irq_xlate. This is only work for the gic */ + + return dt_irq_xlate(raw->specifier, raw->size, + &out_irq->irq, &out_irq->type); +} + +int dt_device_get_irq(const struct dt_device_node *device, int index, + struct dt_irq *out_irq) +{ + struct dt_raw_irq raw; + int res; + + res = dt_device_get_raw_irq(device, index, &raw); + + if ( res ) + return res; + + return dt_irq_translate(&raw, out_irq); +} + +/** * unflatten_dt_node - Alloc and populate a device_node from the flat tree * @fdt: The parent device tree blob * @mem: Memory chunk to use for allocating device nodes and properties @@ -1389,6 +1735,22 @@ static void __init dt_alias_scan(void) } } +struct dt_device_node * __init dt_find_interrupt_controller(const char *compat) +{ + struct dt_device_node *np = NULL; + + while ( (np = dt_find_compatible_node(np, NULL, compat)) ) + { + if ( !dt_find_property(np, "interrupt-controller", NULL) ) + continue; + + if ( dt_get_parent(np) ) + break; + } + + return np; +} + void __init dt_unflatten_host_device_tree(void) { __unflatten_device_tree(device_tree_flattened, &dt_host); diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 020a3d0..c897eab 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -101,6 +101,36 @@ struct dt_device_node { }; +/** + * dt_irq - describe an IRQ in the device tree + * @irq: IRQ number + * @type: IRQ type (see IRQ_TYPE_* in include/xen/irq.h) + * + * This structure is returned when an interrupt is mapped. + */ +struct dt_irq { + unsigned int irq; + unsigned int type; +}; + +/** + * dt_raw_irq - container for device_node/irq_specifier for an irq controller + * @controller: pointer to interrupt controller deivce tree node + * @size: size of interrupt specifier + * @specifier: array of cells @size long specifing the specific interrupt + * + * This structure is returned when an interrupt is mapped but not translated. + */ +#define DT_MAX_IRQ_SPEC 4 /* We handle specifiers of at most 4 cells */ +struct dt_raw_irq { + const struct dt_device_node *controller; + u32 size; + u32 specifier[DT_MAX_IRQ_SPEC]; +}; + +#define dt_irq(irq) ((irq)->irq) +#define dt_irq_flags(irq) ((irq)->flags) + typedef int (*device_tree_node_func)(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, @@ -142,11 +172,40 @@ void __init dt_unflatten_host_device_tree(void); void __init dt_switch_to_printk(void); /** + * IRQ translation callback + * TODO: For the moment we assume that we only have ONE + * interrupt-controller. + */ +typedef int (*dt_irq_xlate_func)(const u32 *intspec, unsigned int intsize, + unsigned int *out_hwirq, + unsigned int *out_type); +extern dt_irq_xlate_func dt_irq_xlate; + +/** * Host device tree * DO NOT modify it! */ extern struct dt_device_node *dt_host; +/** + * Primary interrupt controller + * Exynos SOC has an interrupt combiner, interrupt has no physical + * meaning when it''s not connected to the primary controller. + * We will only map interrupt whose parent controller is + * dt_interrupt_controller. It should always be a GIC. + * TODO: Handle multiple GIC + */ +extern const struct dt_device_node *dt_interrupt_controller; + +/** + * Find the interrupt controller + * For the moment we handle only one interrupt controller: the first + * one without parent and is compatible with the string "compat". + * + * If found, return the interrupt controller device node. + */ +struct dt_device_node * __init dt_find_interrupt_controller(const char *compat); + #define dt_node_cmp(s1, s2) strcmp((s1), (s2)) #define dt_compat_cmp(s1, s2, l) strnicmp((s1), (s2), l) @@ -291,6 +350,15 @@ int dt_device_get_address(const struct dt_device_node *dev, int index, u64 *addr, u64 *size); /** + * dt_number_of_irq - Get the number of IRQ for a device + * @device: the device whose number of interrupt is to be retrieved + * + * Return the number of irq for this device or 0 if there is no + * interrupt or an error occurred. + */ +unsigned int dt_number_of_irq(const struct dt_device_node *device); + +/** * dt_number_of_address - Get the number of addresse for a device * @device: the device whose number of address is to be retrieved * @@ -300,6 +368,37 @@ int dt_device_get_address(const struct dt_device_node *dev, int index, unsigned int dt_number_of_address(const struct dt_device_node *device); /** + * dt_device_get_irq - Resolve an interrupt for a device + * @device: the device whose interrupt is to be resolved + * @index: index of the interrupt to resolve + * @out_irq: structure dt_irq filled by this function + * + * This function resolves an interrupt, walking the tree, for a given + * device-tree node. It''s the high level pendant to dt_device_get_raw_irq(). + */ +int dt_device_get_irq(const struct dt_device_node *device, int index, + struct dt_irq *irq); + +/** + * dt_device_get_raw_irq - Resolve an interrupt for a device without translation + * @device: the device whose interrupt is to be resolved + * @index: index of the interrupt to resolve + * @out_irq: structure dt_raw_irq filled by this function + * + * This function resolves an interrupt for a device, no translation is + * made. dt_irq_translate can be called after. + */ +int dt_device_get_raw_irq(const struct dt_device_node *device, int index, + struct dt_raw_irq *irq); + +/** + * dt_irq_transalte - Translate an irq + * @raw: IRQ to translate (raw format) + * @out_irq: structure dt_irq filled by this function + */ +int dt_irq_translate(const struct dt_raw_irq *raw, struct dt_irq *out_irq); + +/** * dt_n_size_cells - Helper to retrieve the number of cell for the size * @np: node to get the value * diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h index 7386358..42dc172 100644 --- a/xen/include/xen/irq.h +++ b/xen/include/xen/irq.h @@ -33,6 +33,31 @@ struct irqaction { #define NEVER_ASSIGN_IRQ (-2) #define FREE_TO_ASSIGN_IRQ (-3) +/** + * IRQ line type. + * + * IRQ_TYPE_NONE - default, unspecified type + * IRQ_TYPE_EDGE_RISING - rising edge triggered + * IRQ_TYPE_EDGE_FALLING - falling edge triggered + * IRQ_TYPE_EDGE_BOTH - rising and falling edge triggered + * IRQ_TYPE_LEVEL_HIGH - high level triggered + * IRQ_TYPE_LEVEL_LOW - low level triggered + * IRQ_TYPE_LEVEL_MASK - Mask to filter out the level bits + * IRQ_TYPE_SENSE_MASK - Mask for all the above bits + */ +#define IRQ_TYPE_NONE 0x00000000 +#define IRQ_TYPE_EDGE_RISING 0x00000001 +#define IRQ_TYPE_EDGE_FALLING 0x00000002 +#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) +#define IRQ_TYPE_LEVEL_HIGH 0x00000004 +#define IRQ_TYPE_LEVEL_LOW 0x00000008 +#define IRQ_TYPE_LEVEL_MASK (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH) +#define IRQ_TYPE_SENSE_MASK 0x0000000f + +/* If type == IRQ_TYPE_NONE, assume we use level triggered */ +#define irq_is_level_trigger(irq) \ + (((irq)->type & IRQ_TYPE_LEVEL_MASK) || ((irq)->type == IRQ_TYPE_NONE)) + struct irq_desc; /* -- Julien Grall
This function routes an IRQ to a specific cpu. The IRQ is retrieved via the device tree. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 11 +++++++++++ xen/include/asm-arm/gic.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index bac2af2..e03bb67 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -238,6 +238,17 @@ static int gic_route_irq(unsigned int irq, bool_t level, return 0; } +/* Program the GIC to route an interrupt with a dt_irq */ +void gic_route_dt_irq(const struct dt_irq *irq, unsigned int cpu_mask, + unsigned int priority) +{ + bool_t level; + + level = irq_is_level_trigger(irq); + + gic_route_irq(irq->irq, level, cpu_mask, priority); +} + static void __init gic_dist_init(void) { uint32_t type; diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index c3f87e1..2fac673 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -133,6 +133,8 @@ #define VGIC_IRQ_EVTCHN_CALLBACK 31 #ifndef __ASSEMBLY__ +#include <xen/device_tree.h> + extern int domain_vgic_init(struct domain *d); extern void domain_vgic_free(struct domain *d); @@ -141,6 +143,9 @@ extern int vcpu_vgic_init(struct vcpu *v); extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq,int virtual); extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq); +/* Program the GIC to route an interrupt with a dt_irq */ +extern void gic_route_dt_irq(const struct dt_irq *irq, unsigned int cpu_mask, + unsigned int priority); extern void gic_route_ppis(void); extern void gic_route_spis(void); -- Julien Grall
This function translates an interrupt specifier to an IRQ number and IRQ type (ie: level trigger, edge trigger,...). It''s GIC specific. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 20 ++++++++++++++++++++ xen/arch/arm/setup.c | 1 + xen/include/asm-arm/gic.h | 4 ++++ 3 files changed, 25 insertions(+) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index e03bb67..1f44fea 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -329,6 +329,26 @@ static void __cpuinit gic_hyp_disable(void) GICH[GICH_HCR] = 0; } +int gic_irq_xlate(const u32 *intspec, unsigned int intsize, + unsigned int *out_hwirq, + unsigned int *out_type) +{ + if ( intsize < 3 ) + return -EINVAL; + + /* Get the interrupt number and add 16 to skip over SGIs */ + *out_hwirq = intspec[1] + 16; + + /* For SPIs, we need to add 16 more to get the GIC irq ID number */ + if ( !intspec[0] ) + *out_hwirq += 16; + + if ( out_type ) + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; + + return 0; +} + /* Set up the GIC */ void __init gic_init(void) { diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 77d0879..51f4bba 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -429,6 +429,7 @@ void __init start_xen(unsigned long boot_phys_offset, setup_mm(fdt_paddr, fdt_size); dt_unflatten_host_device_tree(); + dt_irq_xlate = gic_irq_xlate; #ifdef EARLY_UART_ADDRESS /* TODO Need to get device tree or command line for UART address */ diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 2fac673..945e8db 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -187,6 +187,10 @@ extern void send_SGI_allbutself(enum gic_sgi sgi); /* print useful debug info */ extern void gic_dump_info(struct vcpu *v); +/* IRQ translation function for the device tree */ +int gic_irq_xlate(const u32 *intspec, unsigned int intsize, + unsigned int *out_hwirq, unsigned int *out_type); + #endif /* __ASSEMBLY__ */ #endif -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 13/29] xen/arm: Use hierarchical device tree to retrieve GIC information
- Remove early parsing for GIC addresses - Remove hard coded maintenance IRQ number Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 63 ++++++++++++++++++++++++++++------------- xen/common/device_tree.c | 42 --------------------------- xen/include/xen/device_tree.h | 8 ------ 3 files changed, 43 insertions(+), 70 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 1f44fea..9c8049e 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -45,6 +45,7 @@ static struct { paddr_t hbase; /* Address of virtual interface registers */ paddr_t vbase; /* Address of virtual cpu interface registers */ unsigned int lines; + struct dt_irq maintenance; /* IRQ maintenance */ unsigned int cpus; spinlock_t lock; } gic; @@ -352,28 +353,49 @@ int gic_irq_xlate(const u32 *intspec, unsigned int intsize, /* Set up the GIC */ void __init gic_init(void) { + struct dt_device_node *node; + int res; + + node = dt_find_interrupt_controller("arm,cortex-a15-gic"); + if ( !node ) + panic("Unable to find compatible GIC in the device tree\n"); + + dt_device_set_used_by(node, DT_USED_BY_XEN); + + res = dt_device_get_address(node, 0, &gic.dbase, NULL); + if ( res || !gic.dbase || (gic.dbase & ~PAGE_MASK) ) + panic("GIC: Cannot find a valid address for the distributor\n"); + + res = dt_device_get_address(node, 1, &gic.cbase, NULL); + if ( res || !gic.cbase || (gic.cbase & ~PAGE_MASK) ) + panic("GIC: Cannot find a valid address for the CPU\n"); + + res = dt_device_get_address(node, 2, &gic.hbase, NULL); + if ( res || !gic.hbase || (gic.hbase & ~PAGE_MASK) ) + panic("GIC: Cannot find a valid address for the hypervisor\n"); + + res = dt_device_get_address(node, 3, &gic.vbase, NULL); + if ( res || !gic.vbase || (gic.vbase & ~PAGE_MASK) ) + panic("GIC: Cannot find a valid address for the virtual CPU\n"); + + res = dt_device_get_irq(node, 0, &gic.maintenance); + if ( res ) + panic("GIC: Cannot find the maintenance IRQ\n"); + + /* Set the GIC as the primary interrupt controller */ + dt_interrupt_controller = node; + + /* TODO: Add check on distributor, cpu size */ + printk("GIC initialization:\n" " gic_dist_addr=%"PRIpaddr"\n" " gic_cpu_addr=%"PRIpaddr"\n" " gic_hyp_addr=%"PRIpaddr"\n" - " gic_vcpu_addr=%"PRIpaddr"\n", - early_info.gic.gic_dist_addr, early_info.gic.gic_cpu_addr, - early_info.gic.gic_hyp_addr, early_info.gic.gic_vcpu_addr); - if ( !early_info.gic.gic_dist_addr || - !early_info.gic.gic_cpu_addr || - !early_info.gic.gic_hyp_addr || - !early_info.gic.gic_vcpu_addr ) - panic("the physical address of one of the GIC interfaces is missing\n"); - if ( (early_info.gic.gic_dist_addr & ~PAGE_MASK) || - (early_info.gic.gic_cpu_addr & ~PAGE_MASK) || - (early_info.gic.gic_hyp_addr & ~PAGE_MASK) || - (early_info.gic.gic_vcpu_addr & ~PAGE_MASK) ) - panic("GIC interfaces not page aligned.\n"); - - gic.dbase = early_info.gic.gic_dist_addr; - gic.cbase = early_info.gic.gic_cpu_addr; - gic.hbase = early_info.gic.gic_hyp_addr; - gic.vbase = early_info.gic.gic_vcpu_addr; + " gic_vcpu_addr=%"PRIpaddr"\n" + " gic_maintenance_irq=%u\n", + gic.dbase, gic.cbase, gic.hbase, gic.vbase, + gic.maintenance.irq); + set_fixmap(FIXMAP_GICD, gic.dbase >> PAGE_SHIFT, DEV_SHARED); BUILD_BUG_ON(FIXMAP_ADDR(FIXMAP_GICC1) ! FIXMAP_ADDR(FIXMAP_GICC2)-PAGE_SIZE); @@ -464,7 +486,7 @@ void gic_route_ppis(void) { /* XXX should get these from DT */ /* GIC maintenance */ - gic_route_irq(25, 1, 1u << smp_processor_id(), 0xa0); + gic_route_dt_irq(&gic.maintenance, 1u << smp_processor_id(), 0xa0); /* Hypervisor Timer */ gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0); /* Virtual Timer */ @@ -813,7 +835,8 @@ void gic_dump_info(struct vcpu *v) void __cpuinit init_maintenance_interrupt(void) { - request_irq(25, maintenance_interrupt, 0, "irq-maintenance", NULL); + request_irq(gic.maintenance.irq, maintenance_interrupt, + 0, "irq-maintenance", NULL); } /* diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index c623fe2..284b574 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -422,46 +422,6 @@ static void __init process_cpu_node(const void *fdt, int node, cpumask_set_cpu(start, &cpu_possible_map); } -static void __init process_gic_node(const void *fdt, int node, - const char *name, - u32 address_cells, u32 size_cells) -{ - const struct fdt_property *prop; - const u32 *cell; - paddr_t start, size; - int interfaces; - - if ( address_cells < 1 || size_cells < 1 ) - { - early_printk("fdt: node `%s'': invalid #address-cells or #size-cells", - name); - return; - } - - prop = fdt_get_property(fdt, node, "reg", NULL); - if ( !prop ) - { - early_printk("fdt: node `%s'': missing `reg'' property\n", name); - return; - } - - cell = (const u32 *)prop->data; - interfaces = device_tree_nr_reg_ranges(prop, address_cells, size_cells); - if ( interfaces < 4 ) - { - early_printk("fdt: node `%s'': not enough ranges\n", name); - return; - } - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); - early_info.gic.gic_dist_addr = start; - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); - early_info.gic.gic_cpu_addr = start; - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); - early_info.gic.gic_hyp_addr = start; - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); - early_info.gic.gic_vcpu_addr = start; -} - static void __init process_multiboot_node(const void *fdt, int node, const char *name, u32 address_cells, u32 size_cells) @@ -513,8 +473,6 @@ static int __init early_scan_node(const void *fdt, process_memory_node(fdt, node, name, address_cells, size_cells); else if ( device_tree_type_matches(fdt, node, "cpu") ) process_cpu_node(fdt, node, name, address_cells, size_cells); - else if ( device_tree_node_compatible(fdt, node, "arm,cortex-a15-gic") ) - process_gic_node(fdt, node, name, address_cells, size_cells); else if ( device_tree_node_compatible(fdt, node, "xen,multiboot-module" ) ) process_multiboot_node(fdt, node, name, address_cells, size_cells); diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index c897eab..a3502e0 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -31,13 +31,6 @@ struct dt_mem_info { struct membank bank[NR_MEM_BANKS]; }; -struct dt_gic_info { - paddr_t gic_dist_addr; - paddr_t gic_cpu_addr; - paddr_t gic_hyp_addr; - paddr_t gic_vcpu_addr; -}; - struct dt_mb_module { paddr_t start; paddr_t size; @@ -52,7 +45,6 @@ struct dt_module_info { struct dt_early_info { struct dt_mem_info mem; - struct dt_gic_info gic; struct dt_module_info modules; }; -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 14/29] xen/arm: Retrieve timer interrupts from the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 9 ++----- xen/arch/arm/time.c | 59 +++++++++++++++++++++++++++++++++++++++----- xen/include/asm-arm/time.h | 3 +++ 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 9c8049e..ea34e9c 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -484,15 +484,10 @@ void gic_disable_cpu(void) void gic_route_ppis(void) { - /* XXX should get these from DT */ /* GIC maintenance */ gic_route_dt_irq(&gic.maintenance, 1u << smp_processor_id(), 0xa0); - /* Hypervisor Timer */ - gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0); - /* Virtual Timer */ - gic_route_irq(27, 1, 1u << smp_processor_id(), 0xa0); - /* Physical Timer */ - gic_route_irq(30, 1, 1u << smp_processor_id(), 0xa0); + /* Route timer interrupt */ + route_timer_interrupt(); } void gic_route_spis(void) diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c index 82f69d2..63dace2 100644 --- a/xen/arch/arm/time.c +++ b/xen/arch/arm/time.c @@ -19,6 +19,7 @@ #include <xen/config.h> #include <xen/console.h> +#include <xen/device_tree.h> #include <xen/init.h> #include <xen/irq.h> #include <xen/lib.h> @@ -46,6 +47,18 @@ uint64_t __read_mostly boot_count; * register-mapped time source in the SoC. */ unsigned long __read_mostly cpu_khz; /* CPU clock frequency in kHz. */ +/* List of timer''s IRQ */ +enum ppi_nr +{ + PHYS_SECURE_PPI, + PHYS_NONSECURE_PPI, + VIRT_PPI, + HYP_PPI, + MAX_TIMER_PPI, +}; + +static struct dt_irq timer_irq[MAX_TIMER_PPI]; + /*static inline*/ s_time_t ticks_to_ns(uint64_t ticks) { return muldiv64(ticks, SECONDS(1), 1000 * cpu_khz); @@ -90,6 +103,28 @@ static uint32_t calibrate_timer(void) /* Set up the timer on the boot CPU */ int __init init_xen_time(void) { + struct dt_device_node *dev; + int res; + unsigned int i; + + dev = dt_find_compatible_node(NULL, NULL, "arm,armv7-timer"); + if ( !dev ) + panic("Unable to find a compatible timer in the device tree\n"); + + dt_device_set_used_by(dev, DT_USED_BY_XEN); + + /* Retrieve all IRQs for the timer */ + for ( i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++ ) + { + res = dt_device_get_irq(dev, i, &timer_irq[i]); + if ( res ) + panic("Timer: Unable to retrieve IRQ %u from the device tree\n", i); + } + + printk("Generic Timer IRQ: phys=%u hyp=%u virt=%u\n", + timer_irq[PHYS_NONSECURE_PPI].irq, timer_irq[HYP_PPI].irq, + timer_irq[VIRT_PPI].irq); + /* Check that this CPU supports the Generic Timer interface */ if ( !cpu_has_gentimer ) panic("CPU does not support the Generic Timer v1 interface.\n"); @@ -143,7 +178,8 @@ int reprogram_timer(s_time_t timeout) /* Handle the firing timer */ static void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs) { - if ( irq == 26 && READ_SYSREG32(CNTHP_CTL_EL2) & CNTx_CTL_PENDING ) + if ( irq == (timer_irq[HYP_PPI].irq) && + READ_SYSREG32(CNTHP_CTL_EL2) & CNTx_CTL_PENDING ) { /* Signal the generic timer code to do its work */ raise_softirq(TIMER_SOFTIRQ); @@ -151,7 +187,8 @@ static void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs) WRITE_SYSREG32(0, CNTHP_CTL_EL2); } - if (irq == 30 && READ_SYSREG32(CNTP_CTL_EL0) & CNTx_CTL_PENDING ) + if ( irq == (timer_irq[PHYS_NONSECURE_PPI].irq) && + READ_SYSREG32(CNTP_CTL_EL0) & CNTx_CTL_PENDING ) { /* Signal the generic timer code to do its work */ raise_softirq(TIMER_SOFTIRQ); @@ -167,6 +204,15 @@ static void vtimer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs) vgic_vcpu_inject_irq(current, irq, 1); } +/* Route timer''s IRQ on this CPU */ +void __cpuinit route_timer_interrupt(void) +{ + gic_route_dt_irq(&timer_irq[PHYS_NONSECURE_PPI], + 1u << smp_processor_id(), 0xa0); + gic_route_dt_irq(&timer_irq[HYP_PPI], 1u << smp_processor_id(), 0xa0); + gic_route_dt_irq(&timer_irq[VIRT_PPI], 1u << smp_processor_id(), 0xa0); +} + /* Set up the timer interrupt on this CPU */ void __cpuinit init_timer_interrupt(void) { @@ -184,10 +230,11 @@ void __cpuinit init_timer_interrupt(void) WRITE_SYSREG32(0, CNTHP_CTL_EL2); /* Hypervisor''s timer disabled */ isb(); - /* XXX Need to find this IRQ number from devicetree? */ - request_irq(26, timer_interrupt, 0, "hyptimer", NULL); - request_irq(27, vtimer_interrupt, 0, "virtimer", NULL); - request_irq(30, timer_interrupt, 0, "phytimer", NULL); + request_irq(timer_irq[HYP_PPI].irq, timer_interrupt, 0, "hyptimer", NULL); + request_irq(timer_irq[VIRT_PPI].irq, vtimer_interrupt, + 0, "virtimer", NULL); + request_irq(timer_irq[PHYS_NONSECURE_PPI].irq, timer_interrupt, + 2, "phytimer", NULL); } /* Wait a set number of microseconds */ diff --git a/xen/include/asm-arm/time.h b/xen/include/asm-arm/time.h index c16bf08..467bf91 100644 --- a/xen/include/asm-arm/time.h +++ b/xen/include/asm-arm/time.h @@ -12,6 +12,9 @@ struct tm; struct tm wallclock_time(void); +/* Route timer''s IRQ on this CPU */ +extern void __cpuinit route_timer_interrupt(void); + /* Set up the timer interrupt on this CPU */ extern void __cpuinit init_timer_interrupt(void); -- Julien Grall
- Define VGIC base address per domain. For the moment the base addresses to dom0 base addresses. - The number of interrupt lines (ie number of SPIs) is equal to: * 0 for guests * number of host SPIs for dom0 Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 21 ++++++++++++++++++--- xen/arch/arm/vgic.c | 21 +++++++++++++++------ xen/include/asm-arm/domain.h | 5 ++++- xen/include/asm-arm/gic.h | 3 +++ 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index ea34e9c..bf0c1fd 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -56,6 +56,11 @@ static DEFINE_PER_CPU(uint64_t, lr_mask); static unsigned nr_lrs; +unsigned int gic_number_lines(void) +{ + return gic.lines; +} + irq_desc_t *__irq_to_desc(int irq) { if (irq < NR_LOCAL_IRQS) return &this_cpu(local_irq_desc)[irq]; @@ -754,11 +759,21 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq) int gicv_setup(struct domain *d) { + /* TODO: Retrieve distributor and CPU guest base address from the + * guest DTS + * For the moment we use dom0 DTS + */ + d->arch.vgic.dbase = gic.dbase; + d->arch.vgic.cbase = gic.cbase; + + + d->arch.vgic.nr_lines = 0; + /* map the gic virtual cpu interface in the gic cpu interface region of * the guest */ - return map_mmio_regions(d, gic.cbase, - gic.cbase + (2 * PAGE_SIZE) - 1, - gic.vbase); + return map_mmio_regions(d, d->arch.vgic.cbase, + d->arch.vgic.cbase + (2 * PAGE_SIZE) - 1, + gic.vbase); } static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs) diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 6aaafe9..cb39848 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -29,8 +29,6 @@ #include "io.h" #include <asm/gic.h> -#define VGIC_DISTR_BASE_ADDRESS 0x000000002c001000 - #define REG(n) (n/4) /* Number of ranks of interrupt registers for a domain */ @@ -79,7 +77,16 @@ int domain_vgic_init(struct domain *d) int i; d->arch.vgic.ctlr = 0; - d->arch.vgic.nr_lines = 32; + + /** + * Currently nr_lines in vgic and gic doesn''t have the same meanings + * Here nr_lines = number of SPIs + */ + if ( d->domain_id == 0 ) + d->arch.vgic.nr_lines = gic_number_lines() - 32; + else + d->arch.vgic.nr_lines = 0; /* We don''t need SPIs for the guest */ + d->arch.vgic.shared_irqs xmalloc_array(struct vgic_irq_rank, DOMAIN_NR_RANKS(d)); d->arch.vgic.pending_irqs @@ -162,7 +169,7 @@ static int vgic_distr_mmio_read(struct vcpu *v, mmio_info_t *info) struct cpu_user_regs *regs = guest_cpu_user_regs(); register_t *r = select_user_reg(regs, dabt.reg); struct vgic_irq_rank *rank; - int offset = (int)(info->gpa - VGIC_DISTR_BASE_ADDRESS); + int offset = (int)(info->gpa - v->domain->arch.vgic.dbase); int gicd_reg = REG(offset); switch ( gicd_reg ) @@ -375,7 +382,7 @@ static int vgic_distr_mmio_write(struct vcpu *v, mmio_info_t *info) struct cpu_user_regs *regs = guest_cpu_user_regs(); register_t *r = select_user_reg(regs, dabt.reg); struct vgic_irq_rank *rank; - int offset = (int)(info->gpa - VGIC_DISTR_BASE_ADDRESS); + int offset = (int)(info->gpa - v->domain->arch.vgic.dbase); int gicd_reg = REG(offset); uint32_t tr; @@ -597,7 +604,9 @@ write_ignore: static int vgic_distr_mmio_check(struct vcpu *v, paddr_t addr) { - return addr >= VGIC_DISTR_BASE_ADDRESS && addr < (VGIC_DISTR_BASE_ADDRESS+PAGE_SIZE); + struct domain *d = v->domain; + + return (addr >= (d->arch.vgic.dbase)) && (addr < (d->arch.vgic.dbase + PAGE_SIZE)); } const struct mmio_handler vgic_distr_mmio_handler = { diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index 410b8e7..a083eaf 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -90,13 +90,16 @@ struct arch_domain */ spinlock_t lock; int ctlr; - int nr_lines; + int nr_lines; /* Number of SPIs */ struct vgic_irq_rank *shared_irqs; /* * SPIs are domain global, SGIs and PPIs are per-VCPU and stored in * struct arch_vcpu. */ struct pending_irq *pending_irqs; + /* Base address for guest GIC */ + paddr_t dbase; /* Distributor base address */ + paddr_t cbase; /* CPU base address */ } vgic; struct vpl011 { diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 945e8db..127a501 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -187,6 +187,9 @@ extern void send_SGI_allbutself(enum gic_sgi sgi); /* print useful debug info */ extern void gic_dump_info(struct vcpu *v); +/* Number of interrupt lines */ +extern unsigned int gic_number_lines(void); + /* IRQ translation function for the device tree */ int gic_irq_xlate(const u32 *intspec, unsigned int intsize, unsigned int *out_hwirq, unsigned int *out_type); -- Julien Grall
Julien Grall
2013-Apr-28 23:01 UTC
[RFC 16/29] xen/arm: Introduce a generic way to use a device from the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/Makefile | 1 + xen/arch/arm/device.c | 74 ++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/xen.lds.S | 6 ++++ xen/include/asm-arm/device.h | 52 +++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 xen/arch/arm/device.c create mode 100644 xen/include/asm-arm/device.h diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 2106a4f..7a73b79 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -27,6 +27,7 @@ obj-y += vgic.o obj-y += vtimer.o obj-y += vpl011.o obj-y += hvm.o +obj-y += device.o #obj-bin-y += ....o diff --git a/xen/arch/arm/device.c b/xen/arch/arm/device.c new file mode 100644 index 0000000..dc751a9 --- /dev/null +++ b/xen/arch/arm/device.c @@ -0,0 +1,74 @@ +/* + * xen/arch/arm/device.c + * + * Helpers to use a device retrieved via the device tree. + * + * Julien Grall <julien.grall@linaro.org> + * Copyright (C) 2013 Linaro Limited. + * + * 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. + */ + +#include <asm/device.h> +#include <xen/errno.h> +#include <xen/lib.h> + +extern const struct device_desc _sdevice[], _edevice[]; + +static bool_t __init device_is_compatible(const struct device_desc *desc, + const struct dt_device_node *dev) +{ + const char *const *compat; + + if ( !desc->compatible ) + return 0; + + for ( compat = desc->compatible; *compat; compat++ ) + { + if ( dt_device_is_compatible(dev, *compat) ) + return 1; + } + + return 0; +} + +int __init device_init(struct dt_device_node *dev, enum device_type type, + const void *data) +{ + const struct device_desc *desc; + + ASSERT(dev != NULL); + + for ( desc = _sdevice; desc != _edevice; desc++ ) + { + if ( desc->type != type ) + continue; + + if ( device_is_compatible(desc, dev) ) + { + ASSERT(desc->init != NULL); + + return desc->init(dev, data); + } + + } + + return -EBADF; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S index fd755d7..7434e83 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -76,6 +76,12 @@ SECTIONS __lock_profile_end = .; #endif + .dev.info : { + _sdevice = .; + *(.dev.info) + _edevice = .; + } :text + . = ALIGN(PAGE_SIZE); /* Init code and data */ __init_begin = .; .init.text : { diff --git a/xen/include/asm-arm/device.h b/xen/include/asm-arm/device.h new file mode 100644 index 0000000..9e47ca6 --- /dev/null +++ b/xen/include/asm-arm/device.h @@ -0,0 +1,52 @@ +#ifndef __ASM_ARM_DEVICE_H +#define __ASM_ARM_DEVICE_H + +#include <xen/init.h> +#include <xen/device_tree.h> + +enum device_type +{ + DEVICE_SERIAL +}; + +struct device_desc { + /* Device name */ + const char *name; + /* Device type */ + enum device_type type; + /* Array of device tree ''compatible'' strings */ + const char *const *compatible; + /* Device initialization */ + int (*init)(struct dt_device_node *dev, const void *data); +}; + +/** + * device_init - Initialize a device + * @dev: device to initialize + * @type: type of the device (serial, network...) + * @data: specific data for initializing the device + * + * Return 0 on success. + */ +int __init device_init(struct dt_device_node *dev, enum device_type type, + const void *data); + +#define DT_DEVICE_START(_name, _namestr, _type) \ +static const struct device_desc __dev_desc_##_name __used \ +__attribute__((__section__(".dev.info"))) = { \ + .name = _namestr, \ + .type = _type, \ + +#define DT_DEVICE_END \ +}; + +#endif /* __ASM_ARM_DEVICE_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 17/29] xen/arm: New callback in uart_driver to get device tree interrupt structure
The existing function serial_irq doesn''t allow to retrieve if the interrupt is edge or level trigger. Use this function to route all serial IRQs to xen. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 12 ++++++++++++ xen/drivers/char/serial.c | 10 ++++++++++ xen/include/xen/serial.h | 5 +++++ 3 files changed, 27 insertions(+) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index bf0c1fd..8085b6e 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -24,6 +24,7 @@ #include <xen/irq.h> #include <xen/sched.h> #include <xen/errno.h> +#include <xen/serial.h> #include <xen/softirq.h> #include <xen/list.h> #include <xen/device_tree.h> @@ -497,9 +498,20 @@ void gic_route_ppis(void) void gic_route_spis(void) { + int seridx; + const struct dt_irq *irq; + /* XXX should get these from DT */ /* UART */ gic_route_irq(37, 0, 1u << smp_processor_id(), 0xa0); + + for ( seridx = 0; seridx <= SERHND_IDX; seridx++ ) + { + if ( (irq = serial_dt_irq(seridx)) == NULL ) + continue; + + gic_route_dt_irq(irq, 1u << smp_processor_id(), 0xa0); + } } void __init release_irq(unsigned int irq) diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index a3d2b26..0ae7e4d 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -482,6 +482,16 @@ int __init serial_irq(int idx) return -1; } +const struct dt_irq __init *serial_dt_irq(int idx) +{ + if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) && + com[idx].driver && com[idx].driver->dt_irq_get ) + return com[idx].driver->dt_irq_get(&com[idx]); + + return NULL; +} + + void serial_suspend(void) { int i; diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index b932ed4..5de5171 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -71,6 +71,8 @@ struct uart_driver { int (*getc)(struct serial_port *, char *); /* Get IRQ number for this port''s serial line: returns -1 if none. */ int (*irq)(struct serial_port *); + /* Get IRQ device node for this port''s serial line: returns NULL if none. */ + const struct dt_irq *(*dt_irq_get)(struct serial_port *); }; /* ''Serial handles'' are composed from the following fields. */ @@ -120,6 +122,9 @@ void serial_end_log_everything(int handle); /* Return irq number for specified serial port (identified by index). */ int serial_irq(int idx); +/* Return irq device node for specified serial port (identified by index). */ +const struct dt_irq *serial_dt_irq(int idx); + /* Serial suspend/resume. */ void serial_suspend(void); void serial_resume(void); -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 18/29] xen/arm: add generic UART to get the device in the device tree
This generic UART will find the right UART via xen command line with com1=myserial. "myserial" is the alias of the UART in the device tree. Xen will retrieve the information via the device tree and call the initialization function for this specific UART thanks to the device API. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/setup.c | 3 +- xen/drivers/char/Makefile | 1 + xen/drivers/char/arm-uart.c | 76 +++++++++++++++++++++++++++++++++++++++++++ xen/include/xen/serial.h | 8 +++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 xen/drivers/char/arm-uart.c diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 51f4bba..e5d8724 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -434,8 +434,9 @@ void __init start_xen(unsigned long boot_phys_offset, #ifdef EARLY_UART_ADDRESS /* TODO Need to get device tree or command line for UART address */ pl011_init(0, FIXMAP_ADDR(FIXMAP_CONSOLE)); - console_init_preirq(); #endif + arm_uart_init(); + console_init_preirq(); /* FIXME: Do something smarter */ dt_switch_to_printk(); diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile index ab2246d..e68a54a 100644 --- a/xen/drivers/char/Makefile +++ b/xen/drivers/char/Makefile @@ -2,4 +2,5 @@ obj-y += console.o obj-$(HAS_NS16550) += ns16550.o obj-$(HAS_PL011) += pl011.o obj-$(HAS_EHCI) += ehci-dbgp.o +obj-$(CONFIG_ARM) += arm-uart.o obj-y += serial.o diff --git a/xen/drivers/char/arm-uart.c b/xen/drivers/char/arm-uart.c new file mode 100644 index 0000000..e242ae2 --- /dev/null +++ b/xen/drivers/char/arm-uart.c @@ -0,0 +1,76 @@ +/* + * xen/drivers/char/arm-uart.c + * + * Generic ARM uart retrieved via the device tree + * + * Julien Grall <julien.grall@linaro.org> + * Copyright (c) 2013 Linaro Limited. + * + * 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. + */ + +#include <asm/device.h> +#include <asm/early_printk.h> +#include <asm/types.h> +#include <xen/console.h> +#include <xen/device_tree.h> +#include <xen/mm.h> +#include <xen/serial.h> + +/* + * Configure serial port with string: devname + * Where devname is the alias of the device in the device tree + */ +static char __initdata opt_com1[30] = ""; +string_param("com1", opt_com1); + +void __init arm_uart_init(void) +{ + struct dt_device_node *dev; + int ret; + u64 addr, size; + struct serial_arm_defaults defaults; + + if ( !console_has("com1") || !strcmp(opt_com1, "") ) + { + early_printk("No console\n"); + return; + } + + early_printk("Looking for serial console %s\n", opt_com1); + dev = dt_find_node_by_alias(opt_com1); + + if ( !dev ) + { + early_printk("Unable to find device \"%s\"\n", opt_com1); + return; + } + + ret = dt_device_get_address(dev, 0, &addr, &size); + if ( ret ) + { + early_printk("Unable to retrieve the base address of the serial\n"); + return; + } + + clear_fixmap(FIXMAP_CONSOLE); + set_fixmap(FIXMAP_CONSOLE, addr >> PAGE_SHIFT, DEV_SHARED); + + addr = FIXMAP_ADDR(FIXMAP_CONSOLE) + (addr & (PAGE_SIZE - 1)); + + defaults.index = 0; + defaults.register_base_address = addr; + + ret = device_init(dev, DEVICE_SERIAL, &defaults); + + if ( ret ) + early_printk("Unable to initialize serial: %d\n", ret); +} diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 5de5171..2579ce8 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -9,6 +9,7 @@ #ifndef __XEN_SERIAL_H__ #define __XEN_SERIAL_H__ +#include <xen/init.h> #include <xen/spinlock.h> struct cpu_user_regs; @@ -156,6 +157,13 @@ void ns16550_init(int index, struct ns16550_defaults *defaults); void ehci_dbgp_init(void); void pl011_init(int index, unsigned long register_base_address); +/* Default value for UART on ARM boards */ +struct serial_arm_defaults { + int index; /* Serial index */ + unsigned long register_base_address; /* Virtual base address */ +}; +void __init arm_uart_init(void); + struct physdev_dbgp_op; int dbgp_op(const struct physdev_dbgp_op *); -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 19/29] xen/arm: Use device tree API in pl011 UART driver
Allow UART driver to retrieve all its information in the device tree. It''s possible to choose the pl011 driver via the Xen command line. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 4 --- xen/arch/arm/setup.c | 4 --- xen/drivers/char/pl011.c | 63 +++++++++++++++++++++++++++++++++++----------- xen/include/xen/serial.h | 1 - 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 8085b6e..8dba4b6 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -501,10 +501,6 @@ void gic_route_spis(void) int seridx; const struct dt_irq *irq; - /* XXX should get these from DT */ - /* UART */ - gic_route_irq(37, 0, 1u << smp_processor_id(), 0xa0); - for ( seridx = 0; seridx <= SERHND_IDX; seridx++ ) { if ( (irq = serial_dt_irq(seridx)) == NULL ) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index e5d8724..aee491d 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -431,10 +431,6 @@ void __init start_xen(unsigned long boot_phys_offset, dt_unflatten_host_device_tree(); dt_irq_xlate = gic_irq_xlate; -#ifdef EARLY_UART_ADDRESS - /* TODO Need to get device tree or command line for UART address */ - pl011_init(0, FIXMAP_ADDR(FIXMAP_CONSOLE)); -#endif arm_uart_init(); console_init_preirq(); diff --git a/xen/drivers/char/pl011.c b/xen/drivers/char/pl011.c index 8efd08e..411aea5 100644 --- a/xen/drivers/char/pl011.c +++ b/xen/drivers/char/pl011.c @@ -22,9 +22,14 @@ #include <xen/serial.h> #include <xen/init.h> #include <xen/irq.h> +#include <asm/early_printk.h> +#include <xen/device_tree.h> +#include <xen/errno.h> +#include <asm/device.h> static struct pl011 { - unsigned int baud, clock_hz, data_bits, parity, stop_bits, irq; + unsigned int baud, clock_hz, data_bits, parity, stop_bits; + struct dt_irq irq; volatile uint32_t *regs; /* UART with IRQ line: interrupt-driven I/O. */ struct irqaction irqaction; @@ -163,13 +168,13 @@ static void __init pl011_init_postirq(struct serial_port *port) struct pl011 *uart = port->uart; int rc; - if ( uart->irq > 0 ) + if ( uart->irq.irq > 0 ) { uart->irqaction.handler = pl011_interrupt; uart->irqaction.name = "pl011"; uart->irqaction.dev_id = port; - if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 ) - printk("ERROR: Failed to allocate pl011 IRQ %d\n", uart->irq); + if ( (rc = setup_irq(uart->irq.irq, &uart->irqaction)) != 0 ) + printk("ERROR: Failed to allocate pl011 IRQ %d\n", uart->irq.irq); } /* Clear pending error interrupts */ @@ -215,7 +220,14 @@ static int pl011_getc(struct serial_port *port, char *pc) static int __init pl011_irq(struct serial_port *port) { struct pl011 *uart = port->uart; - return ((uart->irq > 0) ? uart->irq : -1); + return ((uart->irq.irq > 0) ? uart->irq.irq : -1); +} + +static const struct dt_irq __init *pl011_dt_irq(struct serial_port *port) +{ + struct pl011 *uart = port->uart; + + return &uart->irq; } static struct uart_driver __read_mostly pl011_driver = { @@ -227,32 +239,55 @@ static struct uart_driver __read_mostly pl011_driver = { .tx_ready = pl011_tx_ready, .putc = pl011_putc, .getc = pl011_getc, - .irq = pl011_irq + .irq = pl011_irq, + .dt_irq_get = pl011_dt_irq, }; -/* TODO: Parse UART config from device-tree or command-line */ - -void __init pl011_init(int index, unsigned long register_base_address) +static int __init pl011_uart_init(struct dt_device_node *dev, + const void *data) { + const struct serial_arm_defaults *defaults = data; struct pl011 *uart; + int res; - if ( (index < 0) || (index > 1) ) - return; + if ( (defaults->index < 0) || (defaults->index > 1) ) + return -EINVAL; - uart = &pl011_com[index]; + uart = &pl011_com[defaults->index]; uart->clock_hz = 0x16e3600; uart->baud = 38400; uart->data_bits = 8; uart->parity = PARITY_NONE; uart->stop_bits = 1; - uart->irq = 37; /* TODO Need to find this from devicetree */ - uart->regs = (uint32_t *) register_base_address; + uart->regs = (uint32_t *) defaults->register_base_address; + + res = dt_device_get_irq(dev, 0, &uart->irq); + if ( res ) + { + early_printk("pl011: Unable to retrieve the IRQ\n"); + return res; + } /* Register with generic serial driver. */ serial_register_uart(uart - pl011_com, &pl011_driver, uart); + + dt_device_set_used_by(dev, DT_USED_BY_XEN); + + return 0; } +static const char const *pl011_dt_compat[] __initdata +{ + "arm,pl011", + NULL +}; + +DT_DEVICE_START(pl011, "PL011 UART", DEVICE_SERIAL) + .compatible = pl011_dt_compat, + .init = pl011_uart_init, +DT_DEVICE_END + /* * Local variables: * mode: C diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 2579ce8..a7d4c6d 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -156,7 +156,6 @@ struct ns16550_defaults { void ns16550_init(int index, struct ns16550_defaults *defaults); void ehci_dbgp_init(void); -void pl011_init(int index, unsigned long register_base_address); /* Default value for UART on ARM boards */ struct serial_arm_defaults { int index; /* Serial index */ -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 20/29] xen/arm: Use the device tree to map the address range and IRQ to dom0
- gic_route_irq_to_guest takes a dt_irq instead of an IRQ number - remove hardcoded address/IRQ Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/domain_build.c | 144 +++++++++++++++++++++++++++++++++++++------ xen/arch/arm/gic.c | 12 ++-- xen/include/asm-arm/gic.h | 3 +- 3 files changed, 136 insertions(+), 23 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index ad0ab35..ced73a7 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -14,6 +14,7 @@ #include <asm/setup.h> #include <asm/gic.h> +#include <xen/irq.h> #include "kernel.h" static unsigned int __initdata opt_dom0_max_vcpus; @@ -30,6 +31,14 @@ static void __init parse_dom0_mem(const char *s) } custom_param("dom0_mem", parse_dom0_mem); +#define DEBUG_DT + +#ifdef DEBUG_DT +# define DPRINT(fmt, args...) printk(XENLOG_DEBUG fmt, ##args) +#else +# define DPRINT(fmt, args...) do {} while ( 0 ) +#endif + /* * Amount of extra space required to dom0''s device tree. No new nodes * are added (yet) but one terminating reserve map entry (16 bytes) is @@ -303,6 +312,122 @@ static int write_nodes(struct domain *d, struct kernel_info *kinfo, return 0; } +/* Map the device in the domain */ +static int map_device(struct domain *d, const struct dt_device_node *dev) +{ + unsigned int nirq; + unsigned int naddr; + unsigned int i; + int res; + struct dt_irq irq; + struct dt_raw_irq rirq; + u64 addr, size; + + nirq = dt_number_of_irq(dev); + naddr = dt_number_of_address(dev); + + DPRINT("%s nirq = %d naddr = %u\n", dt_node_full_name(dev), nirq, naddr); + + /* Map IRQs */ + for ( i = 0; i < nirq; i++ ) + { + res = dt_device_get_raw_irq(dev, i, &rirq); + if ( res ) + { + printk(XENLOG_ERR "Unable to retrieve irq %u for %s\n", + i, dt_node_full_name(dev)); + return res; + } + + /** + * Don''t map IRQ that have no physical meaning + * ie: IRQ whose controller is not the GIC + */ + if ( rirq.controller != dt_interrupt_controller ) + { + DPRINT("irq %u skipped it controller (%s)\n", + i, dt_node_full_name(rirq.controller)); + continue; + } + + res = dt_irq_translate(&rirq, &irq); + if ( res ) + { + printk(XENLOG_ERR "Unable to translate irq %u for %s\n", + i, dt_node_full_name(dev)); + return res; + } + + DPRINT("irq %u = %u type = %#x\n", i, irq.irq, irq.type); + /* Don''t check return because the IRQ can be use by multiple device */ + gic_route_irq_to_guest(d, &irq, dt_node_name(dev)); + } + + /* Map the address ranges */ + for ( i = 0; i < naddr; i++ ) + { + res = dt_device_get_address(dev, i, &addr, &size); + if ( res ) + { + printk(XENLOG_ERR "Unable to retrieve address %u for %s\n", + i, dt_node_full_name(dev)); + return res; + } + + DPRINT("addr %u = %#"PRIx64" - %#"PRIx64"\n", i, addr, addr + size - 1); + + res = map_mmio_regions(d, addr & PAGE_MASK, + PAGE_ALIGN(addr + size) - 1, + addr & PAGE_MASK); + if ( res ) + { + printk(XENLOG_ERR "Unable to map %#"PRIx64" - %#"PRIx64" in dom0\n", + addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1); + return res; + } + } + + return 0; +} + +static int handle_node(struct domain *d, const struct dt_device_node *np) +{ + const struct dt_device_node *child; + int res; + + DPRINT("handle %s\n", dt_node_full_name(np)); + + /* Skip theses nodes and the sub-nodes */ + if ( dt_device_is_compatible(np, "xen,xen") || + dt_device_type_is_equal(np, "memory") || + !strcmp("/chosen", dt_node_full_name(np)) ) + return 0; + + if ( dt_device_used_by(np) != DT_USED_BY_XEN ) + { + res = map_device(d, np); + + if ( res ) + return res; + } + + for ( child = np->child; child != NULL; child = child->sibling ) + { + res = handle_node(d, child); + if ( res ) + return res; + } + + return 0; +} + +static int parse_device_tree(struct domain *d) +{ + ASSERT(dt_host && (dt_host->sibling == NULL)); + + return handle_node(d, dt_host); +} + static int prepare_dtb(struct domain *d, struct kernel_info *kinfo) { void *fdt; @@ -385,24 +510,7 @@ int construct_dom0(struct domain *d) if ( rc < 0 ) return rc; - printk("Map CS2 MMIO regions 1:1 in the P2M %#llx->%#llx\n", 0x18000000ULL, 0x1BFFFFFFULL); - map_mmio_regions(d, 0x18000000, 0x1BFFFFFF, 0x18000000); - printk("Map CS3 MMIO regions 1:1 in the P2M %#llx->%#llx\n", 0x1C000000ULL, 0x1FFFFFFFULL); - map_mmio_regions(d, 0x1C000000, 0x1FFFFFFF, 0x1C000000); - - printk("Routing peripheral interrupts to guest\n"); - /* TODO Get from device tree */ - gic_route_irq_to_guest(d, 34, "timer0"); - /*gic_route_irq_to_guest(d, 37, "uart0"); -- XXX used by Xen*/ - gic_route_irq_to_guest(d, 38, "uart1"); - gic_route_irq_to_guest(d, 39, "uart2"); - gic_route_irq_to_guest(d, 40, "uart3"); - gic_route_irq_to_guest(d, 41, "mmc0-1"); - gic_route_irq_to_guest(d, 42, "mmc0-2"); - gic_route_irq_to_guest(d, 44, "keyboard"); - gic_route_irq_to_guest(d, 45, "mouse"); - gic_route_irq_to_guest(d, 46, "lcd"); - gic_route_irq_to_guest(d, 47, "eth"); + parse_device_tree(d); /* The following loads use the domain''s p2m */ p2m_load_VTTBR(d); diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 8dba4b6..67f54af 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -675,13 +675,14 @@ void gic_inject(void) gic_inject_irq_start(); } -int gic_route_irq_to_guest(struct domain *d, unsigned int irq, +int gic_route_irq_to_guest(struct domain *d, const struct dt_irq *irq, const char * devname) { struct irqaction *action; - struct irq_desc *desc = irq_to_desc(irq); + struct irq_desc *desc = irq_to_desc(irq->irq); unsigned long flags; int retval; + bool_t level; action = xmalloc(struct irqaction); if (!action) @@ -689,6 +690,7 @@ int gic_route_irq_to_guest(struct domain *d, unsigned int irq, action->dev_id = d; action->name = devname; + action->free_on_release = 1; spin_lock_irqsave(&desc->lock, flags); spin_lock(&gic.lock); @@ -696,9 +698,11 @@ int gic_route_irq_to_guest(struct domain *d, unsigned int irq, desc->handler = &gic_guest_irq_type; desc->status |= IRQ_GUEST; - gic_set_irq_properties(irq, 1, 1u << smp_processor_id(), 0xa0); + level = irq_is_level_trigger(irq); + + gic_set_irq_properties(irq->irq, level, 1u << smp_processor_id(), 0xa0); - retval = __setup_irq(desc, irq, action); + retval = __setup_irq(desc, irq->irq, action); if (retval) { xfree(action); goto out; diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h index 127a501..587e745 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -155,7 +155,8 @@ extern int gic_events_need_delivery(void); extern void __cpuinit init_maintenance_interrupt(void); extern void gic_set_guest_irq(struct vcpu *v, unsigned int irq, unsigned int state, unsigned int priority); -extern int gic_route_irq_to_guest(struct domain *d, unsigned int irq, +extern int gic_route_irq_to_guest(struct domain *d, + const struct dt_irq *irq, const char * devname); /* Accept an interrupt from the GIC and dispatch its handler */ -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 21/29] xen/arm: WORKAROUND 1:1 memory mapping for dom0
Currently xen doesn''t implement SYS MMU. When a device will talk with dom0 with DMA request the domain will use GFN instead of MFN. For instance on the arndale board, without this patch the network doesn''t work. The 1:1 mapping is a workaround and MUST be remove as soon as a SYS MMU is implemented in XEN. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/domain_build.c | 51 ++++++++++++++++++++++++------------------- xen/arch/arm/kernel.h | 1 - 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index ced73a7..11298e1 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -66,29 +66,36 @@ static int set_memory_reg(struct domain *d, struct kernel_info *kinfo, int address_cells, int size_cells, u32 *new_cell) { int reg_size = (address_cells + size_cells) * sizeof(*cell); - int l = 0; - u64 start; - u64 size; + paddr_t start; + paddr_t size; + struct page_info *pg; + unsigned int order = get_order_from_bytes(dom0_mem); + int res; + paddr_t spfn; - while ( kinfo->unassigned_mem > 0 && l + reg_size <= len - && kinfo->mem.nr_banks < NR_MEM_BANKS ) - { - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); - if ( size > kinfo->unassigned_mem ) - size = kinfo->unassigned_mem; - device_tree_set_reg(&new_cell, address_cells, size_cells, start, size); - - printk("Populate P2M %#"PRIx64"->%#"PRIx64"\n", start, start + size); - p2m_populate_ram(d, start, start + size); - kinfo->mem.bank[kinfo->mem.nr_banks].start = start; - kinfo->mem.bank[kinfo->mem.nr_banks].size = size; - kinfo->mem.nr_banks++; - kinfo->unassigned_mem -= size; - - l += reg_size; - } + pg = alloc_domheap_pages(d, order, 0); + if ( !pg ) + panic("Failed to allocate contiguous memory for dom0\n"); + + spfn = page_to_mfn(pg); + start = spfn << PAGE_SHIFT; + size = (1 << order) << PAGE_SHIFT; + + // 1:1 mapping + printk("Populate P2M %#"PRIx64"->%#"PRIx64" (1:1 mapping for dom0)\n", + start, start + size); + res = guest_physmap_add_page(d, spfn, spfn, order); - return l; + if ( res ) + panic("Unable to add pages in DOM0: %d\n", res); + + device_tree_set_reg(&new_cell, address_cells, size_cells, start, size); + + kinfo->mem.bank[0].start = start; + kinfo->mem.bank[0].size = size; + kinfo->mem.nr_banks = 1; + + return reg_size; } static int write_properties(struct domain *d, struct kernel_info *kinfo, @@ -434,8 +441,6 @@ static int prepare_dtb(struct domain *d, struct kernel_info *kinfo) int new_size; int ret; - kinfo->unassigned_mem = dom0_mem; - fdt = device_tree_flattened; new_size = fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h index 1776a4d..687f6c4 100644 --- a/xen/arch/arm/kernel.h +++ b/xen/arch/arm/kernel.h @@ -15,7 +15,6 @@ struct kernel_info { #endif void *fdt; /* flat device tree */ - paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */ struct dt_mem_info mem; paddr_t dtb_paddr; -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 22/29] xen/arm: Allow Xen to run on multiple platform without recompilation
Xen can include various platform support (ie: exynos5, versatile express...) and choose during boot time a set of callbacks for the current board. These callbacks will be called in places where each board can have specific code. For the moment the callbacks are: - platform_init: additional initialization for the platform - platform_init_time: some platform (ie: Exynos 5) needs to initialize the timer with an uncommon way - platform_specific_mapping: add mapping to dom0 which are not specified in the device tree - platform_reset: reset the platform Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/Makefile | 1 + xen/arch/arm/domain_build.c | 4 ++ xen/arch/arm/platform.c | 121 ++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/setup.c | 3 + xen/arch/arm/shutdown.c | 2 + xen/arch/arm/time.c | 6 ++ xen/arch/arm/xen.lds.S | 6 ++ xen/include/asm-arm/platform.h | 70 +++++++++++++++++++++++ 8 files changed, 213 insertions(+) create mode 100644 xen/arch/arm/platform.c create mode 100644 xen/include/asm-arm/platform.h diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 7a73b79..981ad78 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -17,6 +17,7 @@ obj-y += p2m.o obj-y += percpu.o obj-y += guestcopy.o obj-y += physdev.o +obj-y += platform.o obj-y += setup.o obj-y += time.o obj-y += smpboot.o diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 11298e1..d6b8086 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -12,6 +12,7 @@ #include <xen/libfdt/libfdt.h> #include <xen/guest_access.h> #include <asm/setup.h> +#include <asm/platform.h> #include <asm/gic.h> #include <xen/irq.h> @@ -516,6 +517,9 @@ int construct_dom0(struct domain *d) return rc; parse_device_tree(d); + rc = platform_specific_mapping(d); + if ( rc < 0 ) + return rc; /* The following loads use the domain''s p2m */ p2m_load_VTTBR(d); diff --git a/xen/arch/arm/platform.c b/xen/arch/arm/platform.c new file mode 100644 index 0000000..ba569ea --- /dev/null +++ b/xen/arch/arm/platform.c @@ -0,0 +1,121 @@ +/* + * xen/arch/arm/platform.c + * + * Helpers to execute platform specific code. + * + * Julien Grall <julien.grall@linaro.org> + * Copyright (C) 2013 Linaro Limited. + * + * 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. + */ + +#include <asm/platform.h> +#include <xen/device_tree.h> +#include <xen/init.h> + +extern const struct platform_desc _splatform[], _eplatform[]; + +/* Pointer to the current platform description */ +static const struct platform_desc *platform; + + +static bool_t __init platform_is_compatible(const struct platform_desc *plat) +{ + const char *const *compat; + + if ( !plat->compatible ) + return 0; + + for ( compat = plat->compatible; *compat; compat++ ) + { + if ( dt_machine_is_compatible(*compat) ) + return 1; + } + + return 0; +} + +/* List of possible platform */ +static void dump_platform_table(void) +{ + const struct platform_desc *p; + + printk("Available platform support:\n"); + + for ( p = _splatform; p != _eplatform; p++ ) + printk(" - %s\n", p->name); +} + +int __init platform_init(void) +{ + int res = 0; + + ASSERT(platform == NULL); + + /* Looking for the platform description */ + for ( platform = _splatform; platform != _eplatform; platform++ ) + { + if ( platform_is_compatible(platform) ) + break; + } + + /* We don''t have specific operations for this platform */ + if ( platform == _eplatform ) + { + /* TODO: List compatible */ + printk(XENLOG_WARNING "WARNING: Unrecognized/unsupported device tree " + "compatible list\n"); + dump_platform_table(); + platform = NULL; + } + else + printk(XENLOG_INFO "Platform: %s\n", platform->name); + + if ( platform && platform->init ) + res = platform->init(); + + return res; +} + +int __init platform_init_time(void) +{ + int res = 0; + + if ( platform && platform->init_time ) + res = platform->init_time(); + + return res; +} + +int __init platform_specific_mapping(struct domain *d) +{ + int res = 0; + + if ( platform && platform->specific_mapping ) + res = platform->specific_mapping(d); + + return res; +} + +void platform_reset(void) +{ + if ( platform && platform->reset ) + platform->reset(); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index aee491d..9721150 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -41,6 +41,7 @@ #include <asm/early_printk.h> #include <asm/gic.h> #include <asm/cpufeature.h> +#include <asm/platform.h> struct cpuinfo_arm __read_mostly boot_cpu_data; @@ -439,6 +440,8 @@ void __init start_xen(unsigned long boot_phys_offset, processor_id(); + platform_init(); + init_xen_time(); gic_init(); diff --git a/xen/arch/arm/shutdown.c b/xen/arch/arm/shutdown.c index c1b60af..a5c2085 100644 --- a/xen/arch/arm/shutdown.c +++ b/xen/arch/arm/shutdown.c @@ -5,6 +5,7 @@ #include <xen/lib.h> #include <xen/mm.h> #include <xen/smp.h> +#include <asm/platform.h> static void raw_machine_reset(void) { @@ -21,6 +22,7 @@ static void raw_machine_reset(void) dsb(); isb(); clear_fixmap(FIXMAP_MISC); #endif + platform_reset(); } static void halt_this_cpu(void *arg) diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c index 63dace2..f01be3f 100644 --- a/xen/arch/arm/time.c +++ b/xen/arch/arm/time.c @@ -33,6 +33,7 @@ #include <asm/time.h> #include <asm/gic.h> #include <asm/cpufeature.h> +#include <asm/platform.h> /* * Unfortunately the hypervisor timer interrupt appears to be buggy in @@ -130,6 +131,11 @@ int __init init_xen_time(void) panic("CPU does not support the Generic Timer v1 interface.\n"); cpu_khz = READ_SYSREG32(CNTFRQ_EL0) / 1000; + + res = platform_init_time(); + if ( res ) + return res; + boot_count = READ_SYSREG64(CNTPCT_EL0); printk("Using generic timer at %lu KHz\n", cpu_khz); diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S index 7434e83..b5c99b7 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -76,6 +76,12 @@ SECTIONS __lock_profile_end = .; #endif + .arch.info : { + _splatform = .; + *(.arch.info) + _eplatform = .; + } :text + .dev.info : { _sdevice = .; *(.dev.info) diff --git a/xen/include/asm-arm/platform.h b/xen/include/asm-arm/platform.h new file mode 100644 index 0000000..c89a4ca --- /dev/null +++ b/xen/include/asm-arm/platform.h @@ -0,0 +1,70 @@ +#ifndef __ASM_ARM_PLATFORM_H +#define __ASM_ARM_PLATFORM_H + +#include <xen/init.h> +#include <xen/sched.h> +#include <xen/mm.h> + +/* Describe specific operation for a board */ +struct platform_desc { + /* Platform name */ + const char *name; + /* Array of device tree ''compatible'' strings */ + const char *const *compatible; + /* Platform initialization */ + int (*init)(void); + int (*init_time)(void); + /* Specific mapping for dom0 */ + int (*specific_mapping)(struct domain *d); + /* Platform reset */ + void (*reset)(void); +}; + +int __init platform_init(void); +int __init platform_init_time(void); +int __init platform_specific_mapping(struct domain *d); +void platform_reset(void); + +/* Helper to read/write a register */ +static inline uint32_t platform_read_register(uint32_t addr) +{ + volatile const uint32_t *reg; + uint32_t value; + + set_fixmap(FIXMAP_MISC, addr >> PAGE_SHIFT, DEV_SHARED); + reg = (uint32_t *)(FIXMAP_ADDR(FIXMAP_MISC) + (addr & ~PAGE_MASK)); + value = *reg; + dsb(); isb(); + clear_fixmap(FIXMAP_MISC); + + return value; +} + +static inline void platform_write_register(uint32_t addr, uint32_t value) +{ + volatile uint32_t *reg; + + set_fixmap(FIXMAP_MISC, addr >> PAGE_SHIFT, DEV_SHARED); + reg = (uint32_t *)(FIXMAP_ADDR(FIXMAP_MISC) + (addr & ~PAGE_MASK)); + *reg = value; + clear_fixmap(FIXMAP_MISC); +} + +#define PLATFORM_START(_name, _namestr) \ +static const struct platform_desc __plat_desc_##_name __used \ +__attribute__((__section__(".arch.info"))) = { \ + .name = _namestr, + +#define PLATFORM_END \ +}; + +#endif /* __ASM_ARM_PLATFORM_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- Julien Grall
This platform contains nearly nothing specific except the reset function. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/platforms/vexpress.c | 26 ++++++++++++++++++++++++++ xen/arch/arm/shutdown.c | 14 -------------- xen/include/asm-arm/config.h | 3 --- xen/include/asm-arm/platforms/vexpress.h | 3 +++ 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/xen/arch/arm/platforms/vexpress.c b/xen/arch/arm/platforms/vexpress.c index fd4ce74..7a9cfec 100644 --- a/xen/arch/arm/platforms/vexpress.c +++ b/xen/arch/arm/platforms/vexpress.c @@ -18,6 +18,7 @@ */ #include <asm/platforms/vexpress.h> +#include <asm/platform.h> #include <xen/mm.h> #define DCC_SHIFT 26 @@ -90,6 +91,31 @@ out: return ret; } +static void vexpress_reset(void) +{ + /* Use the SP810 system controller to force a reset */ + volatile uint32_t *sp810; + set_fixmap(FIXMAP_MISC, SP810_ADDRESS >> PAGE_SHIFT, DEV_SHARED); + sp810 = ((uint32_t *) + (FIXMAP_ADDR(FIXMAP_MISC) + (SP810_ADDRESS & ~PAGE_MASK))); + sp810[0] = 0x3; /* switch to slow mode */ + dsb(); isb(); + sp810[1] = 0x1; /* writing any value to SCSYSSTAT reg will reset system */ + dsb(); isb(); + clear_fixmap(FIXMAP_MISC); +} + +static const char const *vexpress_dt_compat[] __initdata +{ + "arm,vexpress", + NULL +}; + +PLATFORM_START(vexpress, "VERSATILE EXPRESS") + .compatible = vexpress_dt_compat, + .reset = vexpress_reset, +PLATFORM_END + /* * Local variables: * mode: C diff --git a/xen/arch/arm/shutdown.c b/xen/arch/arm/shutdown.c index a5c2085..cf42902 100644 --- a/xen/arch/arm/shutdown.c +++ b/xen/arch/arm/shutdown.c @@ -3,25 +3,11 @@ #include <xen/cpu.h> #include <xen/delay.h> #include <xen/lib.h> -#include <xen/mm.h> #include <xen/smp.h> #include <asm/platform.h> static void raw_machine_reset(void) { - /* XXX get this from device tree */ -#ifdef SP810_ADDRESS - /* Use the SP810 system controller to force a reset */ - volatile uint32_t *sp810; - set_fixmap(FIXMAP_MISC, SP810_ADDRESS >> PAGE_SHIFT, DEV_SHARED); - sp810 = ((uint32_t *) - (FIXMAP_ADDR(FIXMAP_MISC) + (SP810_ADDRESS & ~PAGE_MASK))); - sp810[0] = 0x3; /* switch to slow mode */ - dsb(); isb(); - sp810[1] = 0x1; /* writing any value to SCSYSSTAT reg will reset system */ - dsb(); isb(); - clear_fixmap(FIXMAP_MISC); -#endif platform_reset(); } diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h index e49aac1..1f327c7 100644 --- a/xen/include/asm-arm/config.h +++ b/xen/include/asm-arm/config.h @@ -149,9 +149,6 @@ extern unsigned long frametable_virt_end; #define GIC_CR_OFFSET 0x2000 #define GIC_HR_OFFSET 0x4000 /* Guess work http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/064219.html */ #define GIC_VR_OFFSET 0x6000 /* Virtual Machine CPU interface) */ -/* Board-specific: base address of system controller */ -#define SP810_ADDRESS 0x1C020000 - #endif /* __ARM_CONFIG_H__ */ /* diff --git a/xen/include/asm-arm/platforms/vexpress.h b/xen/include/asm-arm/platforms/vexpress.h index 67f8fef..5cf3aba 100644 --- a/xen/include/asm-arm/platforms/vexpress.h +++ b/xen/include/asm-arm/platforms/vexpress.h @@ -23,6 +23,9 @@ #define V2M_SYS_CFG_OSC4 4 #define V2M_SYS_CFG_OSC5 5 +/* Board-specific: base address of system controller */ +#define SP810_ADDRESS 0x1C020000 + #ifndef __ASSEMBLY__ #include <xen/inttypes.h> -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
Add CONFIG_EARLY_PRINTK options in configs/arm{32,64}.mk to let the user to choose if he wants to have early output, ie before the console is initialized. This code is specific for each UART. When CONFIG_EARLY_PRINTK is enabled, Xen will only be able to run on a board with this UART. If a developper wants to add support for a new UART, he must implement the following function/variable: - early_uart_paddr: variable which contains the physical base address for the UART - early_uart_init: initialize the UART - early_uart_ready: check and wait until the UART can transmit a new character - early_uart_transmit: transmit a character For more details about the parameters of each function, see arm{32,64}/debug-pl011.S comments. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- config/arm32.mk | 11 ++++++ config/arm64.mk | 11 ++++++ xen/arch/arm/Makefile | 2 +- xen/arch/arm/Rules.mk | 9 +++++ xen/arch/arm/arm32/Makefile | 5 ++- xen/arch/arm/arm32/debug-pl011.S | 64 +++++++++++++++++++++++++++++++++ xen/arch/arm/arm32/debug.S | 33 +++++++++++++++++ xen/arch/arm/arm32/head.S | 66 ++++++++++++++++------------------ xen/arch/arm/arm64/Makefile | 3 ++ xen/arch/arm/arm64/debug-pl011.S | 64 +++++++++++++++++++++++++++++++++ xen/arch/arm/arm64/debug.S | 33 +++++++++++++++++ xen/arch/arm/arm64/head.S | 69 +++++++++++++++++------------------- xen/arch/arm/early_printk.c | 16 +-------- xen/include/asm-arm/config.h | 2 -- xen/include/asm-arm/early_printk.h | 2 +- 15 files changed, 298 insertions(+), 92 deletions(-) create mode 100644 xen/arch/arm/arm32/debug-pl011.S create mode 100644 xen/arch/arm/arm32/debug.S create mode 100644 xen/arch/arm/arm64/debug-pl011.S create mode 100644 xen/arch/arm/arm64/debug.S diff --git a/config/arm32.mk b/config/arm32.mk index f64f0c1..83a7767 100644 --- a/config/arm32.mk +++ b/config/arm32.mk @@ -7,6 +7,17 @@ CONFIG_ARM_$(XEN_OS) := y # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: CFLAGS += -marm +# Xen early debugging function +# This is helpful if you are debbuging code that executes before the console +# is initialized. +# Note that selecting this option will limit Xen to a single UART +# definition. Attempting to boot Xen image on a different platform *will +# not work*, so this option should not be enable for Xens that are +# intended to be portable. +# Possible value: +# - none: no early printk +# - pl011: printk with PL011 UART +CONFIG_EARLY_PRINTK := none HAS_PL011 := y # Use only if calling $(LD) directly. diff --git a/config/arm64.mk b/config/arm64.mk index b2457eb..6187df8 100644 --- a/config/arm64.mk +++ b/config/arm64.mk @@ -4,6 +4,17 @@ CONFIG_ARM_$(XEN_OS) := y CFLAGS += #-marm -march= -mcpu= etc +# Xen early debugging function +# This is helpful if you are debbuging code that executes before the console +# is initialized. +# Note that selecting this option will limit Xen to a single UART +# definition. Attempting to boot Xen image on a different platform *will +# not work*, so this option should not be enable for Xens that are +# intended to be portable. +# Possible value: +# - none: no early printk +# - pl011: printk with PL011 UART +CONFIG_EARLY_PRINTK := none HAS_PL011 := y # Use only if calling $(LD) directly. diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 981ad78..498777b 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -2,7 +2,7 @@ subdir-$(arm32) += arm32 subdir-$(arm64) += arm64 subdir-y += platforms -obj-y += early_printk.o +obj-$(EARLY_PRINTK) += early_printk.o obj-y += cpu.o obj-y += domain.o obj-y += domctl.o diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk index a0a14e0..2053b1e 100644 --- a/xen/arch/arm/Rules.mk +++ b/xen/arch/arm/Rules.mk @@ -36,3 +36,12 @@ endif ifneq ($(call cc-option,$(CC),-fvisibility=hidden,n),n) CFLAGS += -DGCC_HAS_VISIBILITY_ATTRIBUTE endif + +EARLY_PRINTK := n + +ifeq ($(CONFIG_EARLY_PRINTK), pl011) +EARLY_PRINTK := y +CONFIG_EARLY_PL011 := y +endif + +CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile index 1ad3364..6af8ca3 100644 --- a/xen/arch/arm/arm32/Makefile +++ b/xen/arch/arm/arm32/Makefile @@ -5,4 +5,7 @@ obj-y += mode_switch.o obj-y += proc-ca15.o obj-y += traps.o -obj-y += domain.o \ No newline at end of file +obj-y += domain.o + +obj-$(EARLY_PRINTK) += debug.o +obj-$(CONFIG_EARLY_PL011) += debug-pl011.o diff --git a/xen/arch/arm/arm32/debug-pl011.S b/xen/arch/arm/arm32/debug-pl011.S new file mode 100644 index 0000000..b00bb1f --- /dev/null +++ b/xen/arch/arm/arm32/debug-pl011.S @@ -0,0 +1,64 @@ +/* + * xen/arch/arm/arm32/debug-pl011.S + * + * PL011 specific debug code + * + * Copyright (c) 2013 Citrix Systems. + * + * 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. + */ + +#include <asm/asm_defns.h> + +#define PL011_UART_BASE_ADDRESS 0x1c090000 + +.globl early_uart_paddr +early_uart_paddr: .word PL011_UART_BASE_ADDRESS + +/* PL011 UART initialization + * r11: UART base address + * Clobber r1 */ +.globl early_uart_init +early_uart_init: + mov r1, #0x0 + str r1, [r11, #0x28] /* -> UARTFBRD (Baud divisor fraction) */ + mov r1, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */ + str r1, [r11, #0x24] /* -> UARTIBRD (Baud divisor integer) */ + mov r1, #0x60 /* 8n1 */ + str r1, [r11, #0x2C] /* -> UARTLCR_H (Line control) */ + ldr r1, =0x00000301 /* RXE | TXE | UARTEN */ + str r1, [r11, #0x30] /* -> UARTCR (Control Register) */ + mov pc, lr + +/* PL011 UART wait UART to be ready to transmit + * r11: UART base address + * Clobber r2 */ +.globl early_uart_ready +early_uart_ready: + ldr r2, [r11, #0x18] /* <- UARTFR (Flag register) */ + tst r2, #0x8 /* Check BUSY bit */ + bne early_uart_ready /* Wait for the UART to be ready */ + mov pc, lr + +/* PL011 UART transmit character + * r2: character to transmit + * r11: UART base address */ +.globl early_uart_transmit +early_uart_transmit: + str r2, [r11] /* -> UARTDR (Data Register) */ + mov pc, lr + +/* + * Local variables: + * mode: ASM + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/arm32/debug.S b/xen/arch/arm/arm32/debug.S new file mode 100644 index 0000000..af1b412 --- /dev/null +++ b/xen/arch/arm/arm32/debug.S @@ -0,0 +1,33 @@ +/* + * xen/arch/arm/arm32/debug.S + * + * Wrapper for early printk + * + * Julien Grall <julien.grall@linaro.org> + * Copyright (c) 2013 Linaro Limited. + * + * 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. + */ + +#include <asm/config.h> + +.globl early_putch +/* Print a character on the UART - this function is called by C + * r0: character to print */ +early_putch: + mov r1, fp /* Preserve fp aka r11 */ + mov r3, lr /* Save link register */ + ldr r11, =FIXMAP_ADDR(FIXMAP_CONSOLE) + bl early_uart_ready + mov r2, r0 + bl early_uart_transmit + mov fp, r1 /* Restore fp */ + mov pc, r3 diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S index 0b4cfde..55781cd 100644 --- a/xen/arch/arm/arm32/head.S +++ b/xen/arch/arm/arm32/head.S @@ -34,7 +34,7 @@ /* Macro to print a string to the UART, if there is one. * Clobbers r0-r3. */ -#ifdef EARLY_UART_ADDRESS +#ifdef EARLY_PRINTK #define PRINT(_s) \ adr r0, 98f ; \ bl puts ; \ @@ -42,9 +42,9 @@ 98: .asciz _s ; \ .align 2 ; \ 99: -#else +#else /* EARLY_PRINTK */ #define PRINT(s) -#endif +#endif /* !EARLY_PRINTK */ .arm @@ -106,8 +106,10 @@ past_zImage: bne 1b boot_cpu: -#ifdef EARLY_UART_ADDRESS - ldr r11, =EARLY_UART_ADDRESS /* r11 := UART base address */ +#ifdef EARLY_PRINTK + ldr r0, =early_uart_paddr /* VA of early_uart_paddr */ + add r0, r0, r10 /* PA of early_uart_paddr */ + ldr r11, [r0] /* r11 := UART base address */ teq r12, #0 /* CPU 0 sets up the UART too */ bleq init_uart PRINT("- CPU ") @@ -216,7 +218,7 @@ skip_bss: bne pt_ready /* console fixmap */ -#ifdef EARLY_UART_ADDRESS +#if defined(EARLY_PRINTK) ldr r1, =xen_fixmap add r1, r1, r10 /* r1 := paddr (xen_fixmap) */ mov r3, #0 @@ -279,7 +281,7 @@ pt_ready: paging: -#ifdef EARLY_UART_ADDRESS +#ifdef EARLY_PRINTK /* Use a virtual address to access the UART. */ ldr r11, =FIXMAP_ADDR(FIXMAP_CONSOLE) #endif @@ -345,58 +347,52 @@ fail: PRINT("- Boot failed -\r\n") 1: wfe b 1b -#ifdef EARLY_UART_ADDRESS -/* Bring up the UART. Specific to the PL011 UART. - * Clobbers r0-r2 */ +#ifdef EARLY_PRINTK +/* Bring up the UART. + * Clobbers r0-r3 */ init_uart: - mov r1, #0x0 - str r1, [r11, #0x28] /* -> UARTFBRD (Baud divisor fraction) */ - mov r1, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */ - str r1, [r11, #0x24] /* -> UARTIBRD (Baud divisor integer) */ - mov r1, #0x60 /* 8n1 */ - str r1, [r11, #0x2C] /* -> UARTLCR_H (Line control) */ - ldr r1, =0x00000301 /* RXE | TXE | UARTEN */ - str r1, [r11, #0x30] /* -> UARTCR (Control Register) */ + mov r3, lr /* Save link register */ + bl early_uart_init adr r0, 1f - b puts + b 2f /* Jump to puts */ 1: .asciz "- UART enabled -\r\n" .align 4 -/* Print early debug messages. Specific to the PL011 UART. +/* Print early debug messages. * r0: Nul-terminated string to print. - * Clobbers r0-r2 */ + * Clobbers r0-r3 */ puts: - ldr r2, [r11, #0x18] /* <- UARTFR (Flag register) */ - tst r2, #0x8 /* Check BUSY bit */ - bne puts /* Wait for the UART to be ready */ + mov r3, lr /* Save link register */ +2: + bl early_uart_ready ldrb r2, [r0], #1 /* Load next char */ teq r2, #0 /* Exit on nul */ - moveq pc, lr - str r2, [r11] /* -> UARTDR (Data Register) */ - b puts + moveq pc, r3 + bl early_uart_transmit + b 2b /* Print a 32-bit number in hex. Specific to the PL011 UART. * r0: Number to print. - * clobbers r0-r3 */ + * clobbers r0-r4 */ putn: + mov r4, lr /* Save link register */ adr r1, hex mov r3, #8 -1: ldr r2, [r11, #0x18] /* <- UARTFR (Flag register) */ - tst r2, #0x8 /* Check BUSY bit */ - bne 1b /* Wait for the UART to be ready */ +1: + bl early_uart_ready and r2, r0, #0xf0000000 /* Mask off the top nybble */ ldrb r2, [r1, r2, lsr #28] /* Convert to a char */ - str r2, [r11] /* -> UARTDR (Data Register) */ + bl early_uart_transmit lsl r0, #4 /* Roll it through one nybble at a time */ subs r3, r3, #1 bne 1b - mov pc, lr + mov pc, r4 hex: .ascii "0123456789abcdef" .align 2 -#else /* EARLY_UART_ADDRESS */ +#else /* EARLY_PRINTK */ init_uart: .global early_puts @@ -404,7 +400,7 @@ early_puts: puts: putn: mov pc, lr -#endif /* EARLY_UART_ADDRESS */ +#endif /* !EARLY_PRINTK */ /* * Local variables: diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile index be41f43..d612f87 100644 --- a/xen/arch/arm/arm64/Makefile +++ b/xen/arch/arm/arm64/Makefile @@ -5,3 +5,6 @@ obj-y += mode_switch.o obj-y += traps.o obj-y += domain.o + +obj-$(EARLY_PRINTK) += debug.o +obj-$(CONFIG_EARLY_PL011) += debug-pl011.o diff --git a/xen/arch/arm/arm64/debug-pl011.S b/xen/arch/arm/arm64/debug-pl011.S new file mode 100644 index 0000000..1f55fcd --- /dev/null +++ b/xen/arch/arm/arm64/debug-pl011.S @@ -0,0 +1,64 @@ +/* + * xen/arch/arm/arm64/debug-pl011.S + * + * PL011 specific debug code + * + * Copyright (c) 2013 Citrix Systems. + * + * 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. + */ + +#include <asm/asm_defns.h> + +#define PL011_UART_BASE_ADDRESS 0x1c090000 + +.globl early_uart_paddr +early_uart_paddr: .dword PL011_UART_BASE_ADDRESS + +/* PL011 UART initialization + * x23: UART base address + * Clobber x1 */ +.globl early_uart_init +early_uart_init: + mov x1, #0x0 + strh w1, [x23, #0x28] /* -> UARTFBRD (Baud divisor fraction) */ + mov x1, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */ + strh w1, [x23, #0x24] /* -> UARTIBRD (Baud divisor integer) */ + mov x1, #0x60 /* 8n1 */ + str w1, [x23, #0x2C] /* -> UARTLCR_H (Line control) */ + ldr x1, =0x00000301 /* RXE | TXE | UARTEN */ + str w1, [x23, #0x30] /* -> UARTCR (Control Register) */ + ret + +/* PL011 UART wait UART to be ready to transmit + * x23: UART base address + * Clobber x2 */ +.globl early_uart_ready +early_uart_ready: + ldrh w2, [x23, #0x18] /* <- UARTFR (Flag register) */ + tst w2, #0x8 /* Check BUSY bit */ + b.ne early_uart_ready /* Wait for the UART to be ready */ + ret + +/* PL011 UART transmit character + * x2: character to transmit + * x23: UART base address */ +.globl early_uart_transmit +early_uart_transmit: + strb w2, [x23] /* -> UARTDR (Data Register) */ + ret + +/* + * Local variables: + * mode: ASM + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/arm64/debug.S b/xen/arch/arm/arm64/debug.S new file mode 100644 index 0000000..d1d5b36 --- /dev/null +++ b/xen/arch/arm/arm64/debug.S @@ -0,0 +1,33 @@ +/* + * xen/arch/arm/arm64/debug.S + * + * Wrapper for early printk + * + * Julien Grall <julien.grall@linaro.org> + * Copyright (c) 2013 Linaro Limited. + * + * 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. + */ + +#include <asm/config.h> + +.globl early_putch +/* Print a charact on the UART - this function is called by C + * x0: character to print */ +early_putch: + mov x3, x30 /* Save link register */ + ldr x23, =FIXMAP_ADDR(FIXMAP_CONSOLE) + bl early_uart_ready + mov x2, x0 + bl early_uart_transmit + + mov x30, x3 /* Restore link register */ + ret diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S index ef02899..9908a12 100644 --- a/xen/arch/arm/arm64/head.S +++ b/xen/arch/arm/arm64/head.S @@ -30,8 +30,8 @@ #define PT_DEV_L3 0xe73 /* nG=1 AF=1 SH=10 AP=01 NS=1 ATTR=100 T=1 P=1 */ /* Macro to print a string to the UART, if there is one. - * Clobbers r0-r3. */ -#ifdef EARLY_UART_ADDRESS + * Clobbers x0-x3. */ +#ifdef EARLY_PRINTK #define PRINT(_s) \ adr x0, 98f ; \ bl puts ; \ @@ -39,9 +39,9 @@ 98: .asciz _s ; \ .align 2 ; \ 99: -#else +#else /* EARLY_PRINTK */ #define PRINT(s) -#endif +#endif /* !EARLY_PRINTK */ /*.aarch64*/ @@ -109,8 +109,10 @@ real_start: 2: boot_cpu: -#ifdef EARLY_UART_ADDRESS - ldr x23, =EARLY_UART_ADDRESS /* x23 := UART base address */ +#ifdef EARLY_PRINTK + ldr x0, =early_uart_paddr /* VA of early_uart_paddr */ + add x0, x0, x20 /* PA of early_uart_paddr */ + ldr x23, [x0] /* x23 := UART base address */ cbnz x22, 1f bl init_uart /* CPU 0 sets up the UART too */ 1: PRINT("- CPU ") @@ -206,7 +208,6 @@ skip_bss: mov x4, x1 /* Next level into xen_first */ /* console fixmap */ -#ifdef EARLY_UART_ADDRESS ldr x1, =xen_fixmap add x1, x1, x20 /* x1 := paddr (xen_fixmap) */ lsr x2, x23, #12 @@ -214,7 +215,6 @@ skip_bss: mov x3, #PT_DEV_L3 orr x2, x2, x3 /* x2 := 4K dev map including UART */ str x2, [x1, #(FIXMAP_CONSOLE*8)] /* Map it in the first fixmap''s slot */ -#endif /* Build the baseline idle pagetable''s first-level entries */ ldr x1, =xen_second @@ -266,10 +266,8 @@ pt_ready: br x1 /* Get a proper vaddr into PC */ paging: -#ifdef EARLY_UART_ADDRESS /* Use a virtual address to access the UART. */ ldr x23, =FIXMAP_ADDR(FIXMAP_CONSOLE) -#endif PRINT("- Ready -\r\n") @@ -329,60 +327,57 @@ fail: PRINT("- Boot failed -\r\n") 1: wfe b 1b -#ifdef EARLY_UART_ADDRESS +#ifdef EARLY_PRINTK -/* Bring up the UART. Specific to the PL011 UART. - * Clobbers r0-r2 */ +/* Bring up the UART. + * Clobbers x0-x3 */ init_uart: - mov x1, #0x0 - strh w1, [x23, #0x24] /* -> UARTIBRD (Baud divisor fraction) */ - mov x1, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */ - strh w1, [x23, #0x24] /* -> UARTIBRD (Baud divisor integer) */ - mov x1, #0x60 /* 8n1 */ - strh w1, [x23, #0x24] /* -> UARTLCR_H (Line control) */ - ldr x1, =0x00000301 /* RXE | TXE | UARTEN */ - strh w1, [x23, #0x30] /* -> UARTCR (Control Register) */ + mov x3, x30 /* Save link register */ + bl early_uart_init adr x0, 1f - b puts + b 2f /* Jump to puts */ 1: .asciz "- UART enabled -\r\n" .align 4 -/* Print early debug messages. Specific to the PL011 UART. - * r0: Nul-terminated string to print. - * Clobbers r0-r2 */ +/* Print early debug messages. + * x0: Nul-terminated string to print. + * Clobbers x0-x3 */ puts: - ldrh w2, [x23, #0x18] /* <- UARTFR (Flag register) */ - tst w2, #0x8 /* Check BUSY bit */ - b.ne puts /* Wait for the UART to be ready */ + mov x3, x30 /* Save link register */ +2: + bl early_uart_ready ldrb w2, [x0], #1 /* Load next char */ cbz w2, 1f /* Exit on nul */ - str w2, [x23] /* -> UARTDR (Data Register) */ + bl early_uart_transmit b puts + 1: + mov x30, x3 /* Restore link register */ ret /* Print a 32-bit number in hex. Specific to the PL011 UART. - * r0: Number to print. - * clobbers r0-r3 */ + * x0: Number to print. + * clobbers x0-x4 */ putn: + mov x4, x30 /* Save link register */ adr x1, hex mov x3, #8 -1: ldrh w2, [x23, #0x18] /* <- UARTFR (Flag register) */ - tst w2, #0x8 /* Check BUSY bit */ - b.ne 1b /* Wait for the UART to be ready */ +1: + bl early_uart_ready and x2, x0, #0xf0000000 /* Mask off the top nybble */ lsr x2, x2, #28 ldrb w2, [x1, x2] /* Convert to a char */ - strb w2, [x23] /* -> UARTDR (Data Register) */ + bl early_uart_transmit lsl x0, x0, #4 /* Roll it through one nybble at a time */ subs x3, x3, #1 b.ne 1b + mov x30, x3 /* Restore link register */ ret hex: .ascii "0123456789abcdef" .align 2 -#else /* EARLY_UART_ADDRESS */ +#else /* EARLY_PRINTK */ init_uart: .global early_puts @@ -390,4 +385,4 @@ early_puts: puts: putn: ret -#endif /* EARLY_UART_ADDRESS */ +#endif /* EARLY_PRINTK */ diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c index b21f572..7df511a 100644 --- a/xen/arch/arm/early_printk.c +++ b/xen/arch/arm/early_printk.c @@ -15,19 +15,7 @@ #include <xen/string.h> #include <asm/early_printk.h> -#ifdef EARLY_UART_ADDRESS - -void __init early_putch(char c) -{ - volatile uint32_t *r; - - r = (uint32_t *)(XEN_VIRT_START + (1 << 21)); - - /* XXX: assuming a PL011 UART. */ - while(*(r + 0x6) & 0x8) - ; - *r = c; -} +void early_putch(char c); static void __init early_puts(const char *s) { @@ -67,5 +55,3 @@ early_panic(const char *fmt, ...) while(1); } - -#endif /* #ifdef EARLY_UART_ADDRESS */ diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h index 1f327c7..943175f 100644 --- a/xen/include/asm-arm/config.h +++ b/xen/include/asm-arm/config.h @@ -141,8 +141,6 @@ extern unsigned long frametable_virt_end; #define watchdog_disable() ((void)0) #define watchdog_enable() ((void)0) -/* Board-specific: base address of PL011 UART */ -#define EARLY_UART_ADDRESS 0x1c090000 /* Board-specific: base address of GIC + its regs */ #define GIC_BASE_ADDRESS 0x2c000000 #define GIC_DR_OFFSET 0x1000 diff --git a/xen/include/asm-arm/early_printk.h b/xen/include/asm-arm/early_printk.h index a0297a7..b72fce7 100644 --- a/xen/include/asm-arm/early_printk.h +++ b/xen/include/asm-arm/early_printk.h @@ -12,7 +12,7 @@ #include <xen/config.h> -#ifdef EARLY_UART_ADDRESS +#ifdef EARLY_PRINTK void early_printk(const char *fmt, ...); void early_panic(const char *fmt, ...) __attribute__((noreturn)); -- Julien Grall
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- config/arm32.mk | 1 + xen/drivers/char/Makefile | 1 + xen/drivers/char/exynos5-uart.c | 346 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 348 insertions(+) create mode 100644 xen/drivers/char/exynos5-uart.c diff --git a/config/arm32.mk b/config/arm32.mk index 83a7767..593a1d1 100644 --- a/config/arm32.mk +++ b/config/arm32.mk @@ -19,6 +19,7 @@ CFLAGS += -marm # - pl011: printk with PL011 UART CONFIG_EARLY_PRINTK := none HAS_PL011 := y +HAS_EXYNOS5 := y # Use only if calling $(LD) directly. #LDFLAGS_DIRECT_OpenBSD = _obsd diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile index e68a54a..12a4b49 100644 --- a/xen/drivers/char/Makefile +++ b/xen/drivers/char/Makefile @@ -1,6 +1,7 @@ obj-y += console.o obj-$(HAS_NS16550) += ns16550.o obj-$(HAS_PL011) += pl011.o +obj-$(HAS_EXYNOS5) += exynos5-uart.o obj-$(HAS_EHCI) += ehci-dbgp.o obj-$(CONFIG_ARM) += arm-uart.o obj-y += serial.o diff --git a/xen/drivers/char/exynos5-uart.c b/xen/drivers/char/exynos5-uart.c new file mode 100644 index 0000000..1bae153 --- /dev/null +++ b/xen/drivers/char/exynos5-uart.c @@ -0,0 +1,346 @@ +/* + * xen/drivers/char/exynos5-uart.c + * + * Driver for Exynos 4210 UART. + * + * Anthony PERARD <anthony.perard@citrix.com> + * Copyright (c) 2012 Citrix Systems. + * + * 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. + */ + +#include <xen/config.h> +#include <xen/console.h> +#include <xen/errno.h> +#include <xen/serial.h> +#include <xen/init.h> +#include <xen/irq.h> +#include <asm/early_printk.h> +#include <asm/device.h> + +static struct exynos5_uart { + unsigned int baud, clock_hz, data_bits, parity, stop_bits; + struct dt_irq irq; + volatile uint32_t *regs; + struct irqaction irqaction; +} exynos5_com[2] = {{0}}; + +/* register addresses */ +#define ULCON (0x00/4) +#define UCON (0x04/4) +#define UFCON (0x08/4) +#define UMCON (0x0c/4) +#define UTRSTAT (0x10/4) +#define UERSTAT (0x14/4) +#define UFSTAT (0x18/4) +#define UMSTAT (0x1c/4) +#define UTXH (0x20/4) +#define URXH (0x24/4) +#define UBRDIV (0x28/4) +#define UFRACVAL (0x2c/4) +#define UINTP (0x30/4) +#define UINTS (0x34/4) +#define UINTM (0x38/4) + +/* ULCON */ +#define RXIRQ (0x1<<0) +#define RXDMA (0x2<<0) +#define TXIRQ (0x1<<2) +#define TXDMA (0x2<<2) + +/* UFCON */ +#define FIFO_TX_RESET (1<<2) +#define FIFO_RX_RESET (1<<1) +#define FIFO_EN (1<<0) + +/* UMCON */ +#define INT_EN (1<<3) + +/* UTRSTAT */ +#define TXE (1<<2) +#define TXFE (1<<1) +#define RXDR (1<<0) + +/* Interrupt bits (UINTP, UINTS, UINTM) */ +#define MODEM (1<<3) +#define TXD (1<<2) +#define ERROR (1<<1) +#define RXD (1<<0) +#define ALLI (MODEM|TXD|ERROR|RXD) + +/* These parity settings can be ORed directly into the ULCON. */ +#define PARITY_NONE (0) +#define PARITY_ODD (0x4) +#define PARITY_EVEN (0x5) +#define FORCED_CHECKED_AS_ONE (0x6) +#define FORCED_CHECKED_AS_ZERO (0x7) + +static void exynos5_uart_interrupt(int irq, void *data, struct cpu_user_regs *regs) +{ + struct serial_port *port = data; + struct exynos5_uart *uart = port->uart; + unsigned int status = uart->regs[UINTP]; + + if ( status ) + { + do + { + // clear all pending interrept + // but should take care of ERROR and MODEM + + if ( status & ERROR ) + { + int error_bit = uart->regs[UERSTAT] & 0xf; + if ( error_bit & (1 << 0) ) + printk(XENLOG_ERR "uart: overrun error\n"); + if ( error_bit & (1 << 1) ) + printk(XENLOG_ERR "uart: parity error\n"); + if ( error_bit & (1 << 2) ) + printk(XENLOG_ERR "uart: frame error\n"); + if ( error_bit & (1 << 3) ) + printk(XENLOG_ERR "uart: break detected\n"); + uart->regs[UINTP] = ERROR; + } + + + if ( status & (RXD|ERROR) ) + { + /* uart->regs[UINTM] |= RXD|ERROR; */ + serial_rx_interrupt(port, regs); + /* uart->regs[UINTM] &= ~(RXD|ERROR); */ + uart->regs[UINTP] = RXD|ERROR; + } + + if ( status & (TXD|MODEM) ) + { + /* uart->regs[UINTM] |= TXD|MODEM; */ + serial_tx_interrupt(port, regs); + /* uart->regs[UINTM] &= ~(TXD|MODEM); */ + uart->regs[UINTP] = TXD|MODEM; + } + + status = uart->regs[UINTP]; + } while ( status != 0 ); + } +} + +static void __init exynos5_uart_init_preirq(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + unsigned int divisor; + + /* reset, TX/RX disables */ + uart->regs[UCON] = 0x0; + + /* No Interrupt, auto flow control */ + uart->regs[UMCON] = 0x0; + + /* Line control and baud-rate generator. */ + if ( uart->baud != BAUD_AUTO ) + { + /* Baud rate specified: program it into the divisor latch. */ + // div_val = ubrdiv + ufracval/16 + // or + // div_val = (clock_uart/(baud*16))-1 + divisor = ((uart->clock_hz) / (uart->baud)) - 1; + // FIXME will use a hacked divisor, assuming the src clock and bauds + uart->regs[UFRACVAL] = 53; + uart->regs[UBRDIV] = 4; + /* uart->regs[UFRACVAL] = divisor & 0xf; */ + /* uart->regs[UBRDIV] = divisor >> 4; */ + } + else + { + // TODO, should be updated + /* Baud rate already set: read it out from the divisor latch. */ + //divisor = (uart->regs[IBRD] << 6) | uart->regs[FBRD]; + //uart->baud = (uart->clock_hz << 2) / divisor; + } + uart->regs[ULCON] = ( (uart->data_bits - 5) << 0 + | ((uart->stop_bits - 1) << 2) + | uart->parity << 3 ); + + /* Mask and clear the interrupts */ + uart->regs[UINTM] = ALLI; + uart->regs[UINTP] = ALLI; + + /* enable FIFO */ + uart->regs[UFCON] = FIFO_TX_RESET | FIFO_RX_RESET; + while ( uart->regs[UFCON] & (FIFO_TX_RESET | FIFO_RX_RESET) ) + ; + // reset FIFO_TX_RESET | FIFO_RX_RESET | + uart->regs[UFCON] = (0x6 << 8) | FIFO_EN; + + /* Enable the UART for RX and TX */ + // level tx/rx interrupt,only rx + // enable rx timeout interrupt + uart->regs[UCON] = (0 << 9) | (0 << 8) | RXIRQ | TXIRQ | ( 1 << 7); +} + +static void __init exynos5_uart_init_postirq(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + int rc; + + if ( uart->irq.irq > 0 ) + { + uart->irqaction.handler = exynos5_uart_interrupt; + uart->irqaction.name = "exynos5_uart"; + uart->irqaction.dev_id = port; + if ( (rc = setup_irq(uart->irq.irq, &uart->irqaction)) != 0 ) + printk("ERROR: Failed to allocate exynos5_uart IRQ %d\n", + uart->irq.irq); + + /* Unmask interrupts */ + uart->regs[UINTM] = 0; //MODEM|TXD|ERROR; // only have rx interrupt + + /* Clear pending error interrupts */ + uart->regs[UINTP] = ALLI; + + /* Enable interrupts */ + uart->regs[UMCON] |= INT_EN; + } +} + +static void exynos5_uart_suspend(struct serial_port *port) +{ + BUG(); // XXX +} + +static void exynos5_uart_resume(struct serial_port *port) +{ + BUG(); // XXX +} + +static unsigned int exynos5_uart_tx_ready(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + + // Tx FIFO full + if ( uart->regs[UFSTAT] & (1 << 24) ) + return 0; + else + { + int x = 16 - ((uart->regs[UFSTAT] >> 16) & 0xff); + // Tx FIFO count + if ( x > 0 ) + return x; + else if ( x == 0 ) + return 0; + else { + panic("unwanted value: %d\n", x); + return 0; + } + } +} + +static void exynos5_uart_putc(struct serial_port *port, char c) +{ + struct exynos5_uart *uart = port->uart; + uart->regs[UTXH] = (uint32_t) (unsigned char) c; +} + +static int exynos5_uart_getc(struct serial_port *port, char *pc) +{ + struct exynos5_uart *uart = port->uart; + + // check if rx fifo is full or if there is something in it + if ( (uart->regs[UFSTAT] & (1 << 8)) || (uart->regs[UFSTAT] & 0xff) ) + { + *pc = uart->regs[URXH] & 0xff; + return 1; + } + else + return 0; +} + +static int __init exynos5_uart_irq(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + if ( uart->irq.irq > 0 ) + return uart->irq.irq; + else + return -1; +} + +static const struct dt_irq __init *exynos5_uart_dt_irq(struct serial_port *port) +{ + struct exynos5_uart *uart = port->uart; + + return &uart->irq; +} + +static struct uart_driver __read_mostly exynos5_uart_driver = { + .init_preirq = exynos5_uart_init_preirq, + .init_postirq = exynos5_uart_init_postirq, + .endboot = NULL, + .suspend = exynos5_uart_suspend, + .resume = exynos5_uart_resume, + .tx_ready = exynos5_uart_tx_ready, + .putc = exynos5_uart_putc, + .getc = exynos5_uart_getc, + .irq = exynos5_uart_irq, + .dt_irq_get = exynos5_uart_dt_irq, +}; + +static int __init exynos5_uart_init(struct dt_device_node *dev, + const void *data) +{ + const struct serial_arm_defaults *defaults = data; + struct exynos5_uart *uart; + int res; + + if ( (defaults->index < 0) || (defaults->index > 1) ) + return -EINVAL; + + uart = &exynos5_com[defaults->index]; + + /* uart->clock_hz = 0x16e3600; */ + uart->baud = BAUD_AUTO;//115200; + uart->data_bits = 8; + uart->parity = PARITY_NONE; + uart->stop_bits = 1; + uart->regs = (uint32_t *) defaults->register_base_address; + + res = dt_device_get_irq(dev, 0, &uart->irq); + if ( res ) + { + early_printk("exynos5: Unable to retrieve the IRQ\n"); + return res; + } + + /* Register with generic serial driver. */ + serial_register_uart(uart - exynos5_com, &exynos5_uart_driver, uart); + + dt_device_set_used_by(dev, DT_USED_BY_XEN); + + return 0; +} + +static const char const *exynos5_dt_compat[] __initdata +{ + "samsung,exynos4210-uart", + NULL +}; + +DT_DEVICE_START(exynos5, "Exynos5 UART", DEVICE_SERIAL) + .compatible = exynos5_dt_compat, + .init = exynos5_uart_init, +DT_DEVICE_END + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 26/29] xen/arm: Add Exynos 4210 UART support for early printk
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- config/arm32.mk | 1 + xen/arch/arm/Rules.mk | 4 ++ xen/arch/arm/arm32/Makefile | 1 + xen/arch/arm/arm32/debug-exynos5.S | 81 ++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+) create mode 100644 xen/arch/arm/arm32/debug-exynos5.S diff --git a/config/arm32.mk b/config/arm32.mk index 593a1d1..01c1490 100644 --- a/config/arm32.mk +++ b/config/arm32.mk @@ -17,6 +17,7 @@ CFLAGS += -marm # Possible value: # - none: no early printk # - pl011: printk with PL011 UART +# - exynos5: printk with the second exynos 5 UART CONFIG_EARLY_PRINTK := none HAS_PL011 := y HAS_EXYNOS5 := y diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk index 2053b1e..7dcc0b7 100644 --- a/xen/arch/arm/Rules.mk +++ b/xen/arch/arm/Rules.mk @@ -43,5 +43,9 @@ ifeq ($(CONFIG_EARLY_PRINTK), pl011) EARLY_PRINTK := y CONFIG_EARLY_PL011 := y endif +ifeq ($(CONFIG_EARLY_PRINTK), exynos5) +EARLY_PRINTK := y +CONFIG_EARLY_EXYNOS5 := y +endif CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile index 6af8ca3..90e4eab 100644 --- a/xen/arch/arm/arm32/Makefile +++ b/xen/arch/arm/arm32/Makefile @@ -9,3 +9,4 @@ obj-y += domain.o obj-$(EARLY_PRINTK) += debug.o obj-$(CONFIG_EARLY_PL011) += debug-pl011.o +obj-$(CONFIG_EARLY_EXYNOS5) += debug-exynos5.o diff --git a/xen/arch/arm/arm32/debug-exynos5.S b/xen/arch/arm/arm32/debug-exynos5.S new file mode 100644 index 0000000..cbe1705 --- /dev/null +++ b/xen/arch/arm/arm32/debug-exynos5.S @@ -0,0 +1,81 @@ +/* + * xen/arch/arm/arm32/debug-exynos5.S + * + * Exynos 5 specific debug code + * + * Copyright (c) 2013 Citrix Systems. + * + * 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. + */ + +#include <asm/asm_defns.h> + +#define EXYNOS5_UART_BASE_ADDRESS 0x12c20000 + +.globl early_uart_paddr +early_uart_paddr: .word EXYNOS5_UART_BASE_ADDRESS + +/* Exynos 5 UART initialization + * r11: UART base address + * Clobber r0-r1 */ +.globl early_uart_init +early_uart_init: + /* init clock */ + ldr r1, =0x10020000 + /* select MPLL (800MHz) source clock */ + ldr r0, [r1, #0x250] + and r0, r0, #(~(0xf<<8)) + orr r0, r0, #(0x6<<8) + str r0, [r1, #0x250] + /* ration 800/(7+1) */ + ldr r0, [r1, #0x558] + and r0, r0, #(~(0xf<<8)) + orr r0, r0, #(0x7<<8) + str r0, [r1, #0x558] + + mov r1, #4 + str r1, [r11, #0x2c] /* -> UARTIBRD (Baud divisor fraction) */ + mov r1, #53 + str r1, [r11, #0x28] /* -> UARTIBRD (Baud divisor integer) */ + mov r1, #3 /* 8n1 */ + str r1, [r11, #0x0] /* -> (Line control) */ + ldr r1, =(1<<2) /* TX IRQMODE */ + str r1, [r11, #0x4] /* -> (Control Register) */ + mov r1, #0x0 + str r1, [r11, #0x8] /* disable FIFO */ + mov r1, #0x0 + str r1, [r11, #0x0C] /* no auto flow control */ + mov pc, lr + +/* Exynos 5 UART wait UART to be ready to transmit + * r11: UART base address + * Clobber r2 r11 */ +.globl early_uart_ready +early_uart_ready: + ldr r2, [r11, #0x10] /* <- UTRSTAT (Flag register) */ + tst r2, #(1<<1) /* Check BUSY bit */ + beq early_uart_ready /* Wait for the UART to be ready */ + mov pc, lr + +/* Exynos 5 UART transmit character + * r2: character to transmit + * r11: UART base address */ +.globl early_uart_transmit +early_uart_transmit: + str r2, [r11, #0x20] /* -> UTXH (Data Register) */ + mov pc, lr + +/* + * Local variables: + * mode: ASM + * indent-tabs-mode: nil + * End: + */ -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 27/29] xen/arm: Add platform specific code for the exynos5
Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/platforms/Makefile | 1 + xen/arch/arm/platforms/exynos5.c | 105 +++++++++++++++++++++++++++++++ xen/include/asm-arm/platforms/exynos5.h | 40 ++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 xen/arch/arm/platforms/exynos5.c create mode 100644 xen/include/asm-arm/platforms/exynos5.h diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile index 4313e95..ff2b65b 100644 --- a/xen/arch/arm/platforms/Makefile +++ b/xen/arch/arm/platforms/Makefile @@ -1 +1,2 @@ obj-y += vexpress.o +obj-y += exynos5.o diff --git a/xen/arch/arm/platforms/exynos5.c b/xen/arch/arm/platforms/exynos5.c new file mode 100644 index 0000000..01e12b7 --- /dev/null +++ b/xen/arch/arm/platforms/exynos5.c @@ -0,0 +1,105 @@ +/* + * xen/arch/arm/platforms/exynos5.c + * + * Exynos5 specific settings + * + * Julien Grall <julien.grall@linaro.org> + * Copyright (c) 2013 Linaro Limited. + * + * 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. + */ + +#include <asm/p2m.h> +#include <xen/config.h> +#include <xen/device_tree.h> +#include <xen/domain_page.h> +#include <xen/mm.h> +#include <asm/platforms/exynos5.h> +#include <asm/platform.h> + +static int exynos5_init_time(void) +{ + uint32_t reg; + + // enable timer on exynos5 arndale board + // should probably be done by u-boot + reg = platform_read_register(EXYNOS5_MCT_G_TCON); + platform_write_register(EXYNOS5_MCT_G_TCON, reg | EXYNOS5_MCT_G_TCON_START); + + return 0; +} + +/* Additionnal mapping for dom0 (Not in the DTS) */ +static int exynos5_specific_mapping(struct domain *d) +{ + paddr_t ma = 0; + uint32_t *dst; + int res; + + /* + * Set temporary guest traps with 0xe14fff7c which is hvc(0xfffc) + * a hyp panic! + * TODO: Find why: + * 1) Xen abort directly after local_abort_enable when + * the p2m_populate_ram is not here. + * 2) Linux doesn''t start without this trick + */ + p2m_populate_ram(d, 0x0, 0x1000 - 1); + + res = gvirt_to_maddr(0, &ma); + if ( res ) + { + printk(XENLOG_ERR "Unable to translate guest address\n"); + return -EFAULT; + } + + dst = map_domain_page(ma >> PAGE_SHIFT); + dst[2] = 0xe14fff7c; + unmap_domain_page(dst); + + /* Map the chip ID */ + map_mmio_regions(d, EXYNOS5_PA_CHIPID, EXYNOS5_PA_CHIPID + PAGE_SIZE - 1, + EXYNOS5_PA_CHIPID); + + /* Map the PWM region */ + map_mmio_regions(d, EXYNOS5_PA_TIMER, + EXYNOS5_PA_TIMER + (PAGE_SIZE * 2) - 1, + EXYNOS5_PA_TIMER); + + return 0; +} + +static void exynos5_reset(void) +{ + platform_write_register(EXYNOS5_SWRESET, 1); +} + +static const char const *exynos5_dt_compat[] __initdata +{ + "samsung,exynos5250", + NULL +}; + +PLATFORM_START(exynos5, "SAMSUNG EXYNOS5") + .compatible = exynos5_dt_compat, + .init_time = exynos5_init_time, + .specific_mapping = exynos5_specific_mapping, + .reset = exynos5_reset, +PLATFORM_END + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-arm/platforms/exynos5.h b/xen/include/asm-arm/platforms/exynos5.h new file mode 100644 index 0000000..d77623c --- /dev/null +++ b/xen/include/asm-arm/platforms/exynos5.h @@ -0,0 +1,40 @@ +#ifndef __ASM_ARM_PLATFORMS_EXYNOS5_H +#define __ASM_ASM_PLATFORMS_EXYSNO5_H + +#define EXYNOS5_MCT_BASE 0x101c0000 +#define EXYNOS5_MCTREG(x) (EXYNOS5_MCT_BASE + (x)) +#define EXYNOS5_MCT_G_TCON EXYNOS5_MCTREG(0x240) +#define EXYNOS5_MCT_G_TCON_START (1 << 8) + +#define EXYNOS5_PA_CHIPID 0x10000000 +#define EXYNOS5_PA_TIMER 0x12dd0000 +/* Base address of system controller */ +#define EXYNOS5_PA_PMU 0x10040000 + +#define EXYNOS5_SWRESET (EXYNOS5_PA_PMU + 0x0400) + +#define S5P_PA_SYSRAM 0x02020000 + +/* Constants below is only used in assembly because the DTS is not yet parsed */ +#ifdef __ASSEMBLY__ + +/* GIC Base Address */ +#define EXYNOS5_GIC_BASE_ADDRESS 0x10480000 + +/* Timer''s frequency */ +#define EXYNOS5_TIMER_FREQUENCY (24 * 1000 * 1000) /* 24 MHz */ + +/* Arndale machine ID */ +#define MACH_TYPE_SMDK5250 3774 + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_ARM_PLATFORMS_EXYNOS5_H */ +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 28/29] xen/arm: Support secondary cpus boot and switch to hypervisor for the exynos5
Use machine ID to know what is the current board. This value is only given to the first CPU by the bootloader. When the exynos 5 starts, there is only one CPU up. Xen needs to start the secondary cpu. The latter boots in secure mode. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/arm32/head.S | 19 +++++++- xen/arch/arm/arm32/mode_switch.S | 74 ++++++++++++++++++++++-------- xen/include/asm-arm/platforms/vexpress.h | 11 +++++ 3 files changed, 85 insertions(+), 19 deletions(-) diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S index 55781cd..f701bc0 100644 --- a/xen/arch/arm/arm32/head.S +++ b/xen/arch/arm/arm32/head.S @@ -72,7 +72,7 @@ past_zImage: cpsid aif /* Disable all interrupts */ /* Save the bootloader arguments in less-clobberable registers */ - /* No need to save r1 == Unused ARM-linux machine type */ + mov r5, r1 /* r5: ARM-linux machine type */ mov r8, r2 /* r8 := DTB base address */ /* Find out where we are */ @@ -122,6 +122,20 @@ boot_cpu: teq r12, #0 bleq kick_cpus + /* Secondary CPUs doesn''t have machine ID + * - Store machine on boot CPU + * - Load machine ID on secondary CPUs */ + ldr r0, =machine_id /* VA of machine_id */ + add r0, r0, r10 /* PA of machine_id */ + teq r12, #0 + streq r5, [r0] /* On boot CPU save machine ID */ + ldrne r5, [r0] /* If non boot cpu r5 := machine ID */ + + PRINT("- Machine ID ") + mov r0, r5 + bl putn + PRINT(" -\r\n") + /* Check that this CPU has Hyp mode */ mrc CP32(r0, ID_PFR1) and r0, r0, #0xf000 /* Bits 12-15 define virt extensions */ @@ -402,6 +416,9 @@ putn: mov pc, lr #endif /* !EARLY_PRINTK */ +/* Place holder for machine ID */ +machine_id: .word 0x0 + /* * Local variables: * mode: ASM diff --git a/xen/arch/arm/arm32/mode_switch.S b/xen/arch/arm/arm32/mode_switch.S index d6741d0..ab40f18 100644 --- a/xen/arch/arm/arm32/mode_switch.S +++ b/xen/arch/arm/arm32/mode_switch.S @@ -20,14 +20,20 @@ #include <asm/config.h> #include <asm/page.h> #include <asm/platforms/vexpress.h> +#include <asm/platforms/exynos5.h> #include <asm/asm_defns.h> #include <asm/gic.h> - -/* XXX: Versatile Express specific code */ -/* wake up secondary cpus */ +/* Wake up secondary cpus + * This code relies on Machine ID and only works for Vexpress and the Arndale + * TODO: Move this code either later (via platform specific desc) or in a bootwrapper + * r5: Machine ID + * Clobber r0 r2 */ .globl kick_cpus kick_cpus: + ldr r0, =MACH_TYPE_SMDK5250 + teq r5, r0 /* Are we running on the arndale? */ + beq kick_cpus_arndale /* write start paddr to v2m sysreg FLAGSSET register */ ldr r0, =(V2M_SYS_MMIO_BASE) /* base V2M sysreg MMIO address */ dsb @@ -38,8 +44,20 @@ kick_cpus: add r2, r2, r10 str r2, [r0, #(V2M_SYS_FLAGSSET)] dsb + ldr r2, =V2M_GIC_BASE_ADDRESS /* r2 := VE gic base address */ + b kick_cpus_sgi +kick_cpus_arndale: + /* write start paddr to CPU 1 sysreg register */ + ldr r0, =(S5P_PA_SYSRAM) + ldr r2, =start + add r2, r2, r10 + str r2, [r0] + dsb + ldr r2, =EXYNOS5_GIC_BASE_ADDRESS /* r2 := Exynos5 gic base address */ +kick_cpus_sgi: /* send an interrupt */ - ldr r0, =(GIC_BASE_ADDRESS + GIC_DR_OFFSET) /* base GICD MMIO address */ + ldr r0, =GIC_DR_OFFSET /* GIC distributor offset */ + add r0, r2 /* r0 := r0 + gic base address */ mov r2, #0x1 str r2, [r0, #(GICD_CTLR * 4)] /* enable distributor */ mov r2, #0xfe0000 @@ -51,13 +69,15 @@ kick_cpus: /* Get up a CPU into Hyp mode. Clobbers r0-r3. * - * Expects r12 == CPU number + * r5: Machine ID + * r12: CPU number * - * This code is specific to the VE model, and not intended to be used + * This code is specific to the VE model/Arndale, and not intended to be used * on production systems. As such it''s a bit hackier than the main * boot code in head.S. In future it will be replaced by better * integration with the bootloader/firmware so that Xen always starts - * in Hyp mode. */ + * in Hyp mode. + * Clobber r0 - r4 */ .globl enter_hyp_mode enter_hyp_mode: @@ -68,33 +88,51 @@ enter_hyp_mode: orr r0, r0, #0xb1 /* Set SCD, AW, FW and NS */ bic r0, r0, #0xe /* Clear EA, FIQ and IRQ */ mcr CP32(r0, SCR) + + ldr r2, =MACH_TYPE_SMDK5250 /* r4 := Arndale machine ID */ + /* By default load Arndale defaults values */ + ldr r0, =EXYNOS5_TIMER_FREQUENCY /* r0 := timer''s frequency */ + ldr r1, =EXYNOS5_GIC_BASE_ADDRESS /* r1 := GIC base address */ + /* If it''s not the Arndale machine ID, load VE values */ + teq r5, r2 + ldrne r0, =V2M_TIMER_FREQUENCY + ldrne r1, =V2M_GIC_BASE_ADDRESS + /* Ugly: the system timer''s frequency register is only * programmable in Secure state. Since we don''t know where its * memory-mapped control registers live, we can''t find out the - * right frequency. Use the VE model''s default frequency here. */ - ldr r0, =0x5f5e100 /* 100 MHz */ + * right frequency. */ mcr CP32(r0, CNTFRQ) ldr r0, =0x40c00 /* SMP, c11, c10 in non-secure mode */ mcr CP32(r0, NSACR) - mov r0, #GIC_BASE_ADDRESS - add r0, r0, #GIC_DR_OFFSET + + add r0, r1, #GIC_DR_OFFSET /* Disable the GIC distributor, on the boot CPU only */ - mov r1, #0 + mov r4, #0 teq r12, #0 /* Is this the boot CPU? */ - streq r1, [r0] + streq r4, [r0] /* Continuing ugliness: Set up the GIC so NS state owns interrupts, * The first 32 interrupts (SGIs & PPIs) must be configured on all * CPUs while the remainder are SPIs and only need to be done one, on * the boot CPU. */ add r0, r0, #0x80 /* GICD_IGROUP0 */ mov r2, #0xffffffff /* All interrupts to group 1 */ - teq r12, #0 /* Boot CPU? */ str r2, [r0] /* Interrupts 0-31 (SGI & PPI) */ - streq r2, [r0, #4] /* Interrupts 32-63 (SPI) */ - streq r2, [r0, #8] /* Interrupts 64-95 (SPI) */ + teq r12, #0 /* Boot CPU? */ + bne skip_spis /* Don''t route SPIs on secondary CPUs */ + + add r4, r1, #GIC_DR_OFFSET + ldr r4, [r4, #4] /* r4 := Interrupt Controller Type Reg */ + and r4, r4, #GICD_TYPE_LINES /* r4 := number of SPIs */ + /* Assume we have minimum 32 SPIs */ +1: + add r0, r0, #4 /* Go to the new group */ + str r2, [r0] /* Update the group */ + subs r4, r4, #1 + bne 1b +skip_spis: /* Disable the GIC CPU interface on all processors */ - mov r0, #GIC_BASE_ADDRESS - add r0, r0, #GIC_CR_OFFSET + add r0, r1, #GIC_CR_OFFSET mov r1, #0 str r1, [r0] /* Must drop priority mask below 0x80 before entering NS state */ diff --git a/xen/include/asm-arm/platforms/vexpress.h b/xen/include/asm-arm/platforms/vexpress.h index 5cf3aba..982a293 100644 --- a/xen/include/asm-arm/platforms/vexpress.h +++ b/xen/include/asm-arm/platforms/vexpress.h @@ -32,6 +32,17 @@ int vexpress_syscfg(int write, int function, int device, uint32_t *data); #endif +/* Constants below is only used in assembly because the DTS is not yet parsed */ +#ifdef __ASSEMBLY__ + +/* GIC base address */ +#define V2M_GIC_BASE_ADDRESS 0x2c000000 + +/* Timer''s frequency */ +#define V2M_TIMER_FREQUENCY 0x5f5e100 /* 100 Mhz */ + +#endif /* __ASSEMBLY__ */ + #endif /* __ASM_ARM_PLATFORMS_VEXPRESS_H */ /* * Local variables: -- Julien Grall
Julien Grall
2013-Apr-28 23:02 UTC
[RFC 29/29] xen/arm64: Remove hardcoded value for gic in assembly code
- arm64: use V2M_GIC_BASE_ADDRESS - only expose GIC_*_ADDRESS to assembly. The C code uses base addresses provide by the device tree Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/arm64/mode_switch.S | 7 ++++--- xen/include/asm-arm/config.h | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/xen/arch/arm/arm64/mode_switch.S b/xen/arch/arm/arm64/mode_switch.S index 4c38181..d115706 100644 --- a/xen/arch/arm/arm64/mode_switch.S +++ b/xen/arch/arm/arm64/mode_switch.S @@ -21,6 +21,7 @@ #include <asm/config.h> #include <asm/page.h> #include <asm/asm_defns.h> +#include <asm/platforms/vexpress.h> /* Get up a CPU into EL2. Clobbers x0-x3. * @@ -53,18 +54,18 @@ enter_el2_mode: */ cbnz x22, 1f - ldr x1, =(GIC_BASE_ADDRESS+GIC_DR_OFFSET) // GICD_CTLR + ldr x1, =(V2M_GIC_BASE_ADDRESS+GIC_DR_OFFSET) // GICD_CTLR mov w0, #3 // EnableGrp0 | EnableGrp1 str w0, [x1] -1: ldr x1, =(GIC_BASE_ADDRESS+GIC_DR_OFFSET+0x80) // GICD_IGROUPR +1: ldr x1, =(V2M_GIC_BASE_ADDRESS+GIC_DR_OFFSET+0x80) // GICD_IGROUPR mov w0, #~0 // Grp1 interrupts str w0, [x1], #4 b.ne 2f // Only local interrupts for secondary CPUs str w0, [x1], #4 str w0, [x1], #4 -2: ldr x1, =(GIC_BASE_ADDRESS+GIC_CR_OFFSET) // GICC_CTLR +2: ldr x1, =(V2M_GIC_BASE_ADDRESS+GIC_CR_OFFSET) // GICC_CTLR ldr w0, [x1] mov w0, #3 // EnableGrp0 | EnableGrp1 str w0, [x1] diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h index 943175f..eb13bf4 100644 --- a/xen/include/asm-arm/config.h +++ b/xen/include/asm-arm/config.h @@ -141,12 +141,16 @@ extern unsigned long frametable_virt_end; #define watchdog_disable() ((void)0) #define watchdog_enable() ((void)0) -/* Board-specific: base address of GIC + its regs */ -#define GIC_BASE_ADDRESS 0x2c000000 +#ifdef __ASSEMBLY__ +/* Board-specific: regs base address for the GIC + * Theses constants are only intend to be used in assembly file + * because the DT is not yet parsed.t diff + */ #define GIC_DR_OFFSET 0x1000 #define GIC_CR_OFFSET 0x2000 #define GIC_HR_OFFSET 0x4000 /* Guess work http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/064219.html */ #define GIC_VR_OFFSET 0x6000 /* Virtual Machine CPU interface) */ +#endif /* __ASSEMBLY__ */ #endif /* __ARM_CONFIG_H__ */ /* -- Julien Grall
CCing George, Xen 4.3 release manager. On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> Hello, > > This patch series is divided in 4 parts: > - Patch 1-6: Minor bug fixes > - Patch 7-10: Add hierarchical device tree support based on linux tree > - Patch 11-24: Remove harcoded part > - Patch 25-28: Arndale support based on Anthony''s git > > Xen can boot on both Arndale Board and the Versatile Express without > recompilation. But there is still some hardcoded part, mainly in assembly.I haven''t reviewed this yet but I think this is something we are going to want for the Xen 4.3 release if at all possible. (NB, for Linaro chaps, we are past feature and code freeze and are intending to release 4.3-rc1 next Monday, but there is scope for freeze exceptions to be argued for) Arndale is currently the only widely available/reasonably priced development platform which can run Xen and therefore IMHO Xen 4.3 needs to be able to run on it if it is to be a useful "tech preview" platform. The current xen.git tree runs on the vexpress platform (rather expensive) with the TC2 chip (difficult if not impossible for random developers to get hold of) and the software models (random developers can get an eval license for these, but they don''t last very long). IMHO the priority order of the platforms for 4.3 is, in decreasing order: Arndale Fast Models Vexpress (with vexpress there running a pretty distant third) Obviously there is a risk with these patches of breaking Xen on one or more (or all) of those platforms: I think this is a risk we should take. However this is not worth slipping the Xen release for, in particular it is not reasonable to delay the release for x86 users because we took a risk for a tech preview on ARM. So I propose that we take these patches and see how it goes. I think in practice the rc cycle will be plenty of time to sort out Xen on Arndale for 4.3, but the contingency plan would be to fix it up in 4.3.1 and/or maintain a brief xen-on-arm fork of 4.3. Ian.
On 29/04/13 11:17, Ian Campbell wrote:> CCing George, Xen 4.3 release manager. > > On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> Hello, >> >> This patch series is divided in 4 parts: >> - Patch 1-6: Minor bug fixes >> - Patch 7-10: Add hierarchical device tree support based on linux tree >> - Patch 11-24: Remove harcoded part >> - Patch 25-28: Arndale support based on Anthony''s git >> >> Xen can boot on both Arndale Board and the Versatile Express without >> recompilation. But there is still some hardcoded part, mainly in assembly. > I haven''t reviewed this yet but I think this is something we are going > to want for the Xen 4.3 release if at all possible. (NB, for Linaro > chaps, we are past feature and code freeze and are intending to release > 4.3-rc1 next Monday, but there is scope for freeze exceptions to be > argued for) > > Arndale is currently the only widely available/reasonably priced > development platform which can run Xen and therefore IMHO Xen 4.3 needs > to be able to run on it if it is to be a useful "tech preview" platform. > > The current xen.git tree runs on the vexpress platform (rather > expensive) with the TC2 chip (difficult if not impossible for random > developers to get hold of) and the software models (random developers > can get an eval license for these, but they don''t last very long). IMHO > the priority order of the platforms for 4.3 is, in decreasing order: > Arndale > Fast Models > Vexpress > (with vexpress there running a pretty distant third) > > Obviously there is a risk with these patches of breaking Xen on one or > more (or all) of those platforms: I think this is a risk we should take. > > However this is not worth slipping the Xen release for, in particular it > is not reasonable to delay the release for x86 users because we took a > risk for a tech preview on ARM. So I propose that we take these patches > and see how it goes. I think in practice the rc cycle will be plenty of > time to sort out Xen on Arndale for 4.3, but the contingency plan would > be to fix it up in 4.3.1 and/or maintain a brief xen-on-arm fork of 4.3.Overall I want to defer the goals of the 4.3 ARM stuff to the ARM developers. From this e-mail (and other IRL chats), it seems that there are a couple of possible outcomes: 1. Apply the current x86 code-freeze policy to ARM. The result (IIUC) will be a 4.3 release will not support the Arndale boards. 2. Relax the policy and allow this kind of patch series to be checked in. Possible outcomes are: 2a. Arndale support will be stable by the scheduled 4.3 release 2b. Arndale support will not be stable by the scheduled release; we slip the release as a result 2c. Arndale support will not be stable by the scheduled release; we release anyway with "tech-preview-only" ARM support and fix it up in a subsequent minor point release 2-3 months afterwards. I agree with Ian that 2b should be taken off the table. So the choice now would be between choosing 1, or choosing the un-collapsed waveform {2a, 2c} (a la Schroedinger''s cat). Given that 2c is not really that much worse than 1, and 2a is much better than 1, I think from the ARM perspective it makes sense to accept the series. The only other thing to consider is the potential impact on x86. As long as any changes are highly likely to be detected before the 4.3 release, I think it''s OK: at a last resort we can just revert the change that introduced the bug. The only thing we need to be careful of is not introducing bugs which have a risk of *not* being detected by the 4.3 release. So from a release perspective (assuming that there are no risky x86 changes): Acked-by: George Dunlap <george.dunlap@eu.citrix.com>
On 04/29/2013 11:17 AM, Ian Campbell wrote:> CCing George, Xen 4.3 release manager. > > On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> Hello, >> >> This patch series is divided in 4 parts: >> - Patch 1-6: Minor bug fixes >> - Patch 7-10: Add hierarchical device tree support based on linux tree >> - Patch 11-24: Remove harcoded part >> - Patch 25-28: Arndale support based on Anthony''s git >> >> Xen can boot on both Arndale Board and the Versatile Express without >> recompilation. But there is still some hardcoded part, mainly in assembly. > > I haven''t reviewed this yet but I think this is something we are going > to want for the Xen 4.3 release if at all possible. (NB, for Linaro > chaps, we are past feature and code freeze and are intending to release > 4.3-rc1 next Monday, but there is scope for freeze exceptions to be > argued for) > > Arndale is currently the only widely available/reasonably priced > development platform which can run Xen and therefore IMHO Xen 4.3 needs > to be able to run on it if it is to be a useful "tech preview" platform. > > The current xen.git tree runs on the vexpress platform (rather > expensive) with the TC2 chip (difficult if not impossible for random > developers to get hold of) and the software models (random developers > can get an eval license for these, but they don''t last very long). IMHO > the priority order of the platforms for 4.3 is, in decreasing order: > Arndale > Fast Models > Vexpress > (with vexpress there running a pretty distant third)I have only checked this tree on the Arndale and Fast Models Arm 32. Julien
On 04/29/2013 11:33 AM, George Dunlap wrote:> On 29/04/13 11:17, Ian Campbell wrote: >> CCing George, Xen 4.3 release manager. >> >> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >>> Hello, >>> >>> This patch series is divided in 4 parts: >>> - Patch 1-6: Minor bug fixes >>> - Patch 7-10: Add hierarchical device tree support based on >>> linux tree >>> - Patch 11-24: Remove harcoded part >>> - Patch 25-28: Arndale support based on Anthony''s git >>> >>> Xen can boot on both Arndale Board and the Versatile Express without >>> recompilation. But there is still some hardcoded part, mainly in >>> assembly. >> I haven''t reviewed this yet but I think this is something we are going >> to want for the Xen 4.3 release if at all possible. (NB, for Linaro >> chaps, we are past feature and code freeze and are intending to release >> 4.3-rc1 next Monday, but there is scope for freeze exceptions to be >> argued for) >> >> Arndale is currently the only widely available/reasonably priced >> development platform which can run Xen and therefore IMHO Xen 4.3 needs >> to be able to run on it if it is to be a useful "tech preview" platform. >> >> The current xen.git tree runs on the vexpress platform (rather >> expensive) with the TC2 chip (difficult if not impossible for random >> developers to get hold of) and the software models (random developers >> can get an eval license for these, but they don''t last very long). IMHO >> the priority order of the platforms for 4.3 is, in decreasing order: >> Arndale >> Fast Models >> Vexpress >> (with vexpress there running a pretty distant third) >> >> Obviously there is a risk with these patches of breaking Xen on one or >> more (or all) of those platforms: I think this is a risk we should take. >> >> However this is not worth slipping the Xen release for, in particular it >> is not reasonable to delay the release for x86 users because we took a >> risk for a tech preview on ARM. So I propose that we take these patches >> and see how it goes. I think in practice the rc cycle will be plenty of >> time to sort out Xen on Arndale for 4.3, but the contingency plan would >> be to fix it up in 4.3.1 and/or maintain a brief xen-on-arm fork of 4.3. > > Overall I want to defer the goals of the 4.3 ARM stuff to the ARM > developers. From this e-mail (and other IRL chats), it seems that there > are a couple of possible outcomes: > > 1. Apply the current x86 code-freeze policy to ARM. The result (IIUC) > will be a 4.3 release will not support the Arndale boards. > > 2. Relax the policy and allow this kind of patch series to be checked > in. Possible outcomes are: > 2a. Arndale support will be stable by the scheduled 4.3 release > 2b. Arndale support will not be stable by the scheduled release; we slip > the release as a result > 2c. Arndale support will not be stable by the scheduled release; we > release anyway with "tech-preview-only" ARM support and fix it up in a > subsequent minor point release 2-3 months afterwards. > > I agree with Ian that 2b should be taken off the table. > > So the choice now would be between choosing 1, or choosing the > un-collapsed waveform {2a, 2c} (a la Schroedinger''s cat). > > Given that 2c is not really that much worse than 1, and 2a is much > better than 1, I think from the ARM perspective it makes sense to accept > the series. > > The only other thing to consider is the potential impact on x86. As > long as any changes are highly likely to be detected before the 4.3 > release, I think it''s OK: at a last resort we can just revert the change > that introduced the bug. The only thing we need to be careful of is not > introducing bugs which have a risk of *not* being detected by the 4.3 > release.Most of the code modifies arch/arm and common/device_tree.c. There is one patch which could impact x86 is "[RFC 17/29] xen/arm: New callback in uart_driver to get device tree interrupt structure". Julien
On Mon, 2013-04-29 at 11:33 +0100, George Dunlap wrote:> [...]Good analysis, thanks.> So from a release perspective (assuming that there are no risky x86 > changes): > > Acked-by: George Dunlap <george.dunlap@eu.citrix.com>Cheers, Ian.
Ian Campbell
2013-Apr-29 14:55 UTC
Re: [RFC 01/29] xen/arm: lr must be included in range [0-nr_lr[
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: Typo in subject, [ at the end, did you mean ] or ) ? ( I can never remember which one is inclusive)> Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/gic.c | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c > index bc8faf2..bac2af2 100644 > --- a/xen/arch/arm/gic.c > +++ b/xen/arch/arm/gic.c > @@ -512,7 +512,9 @@ static inline void gic_set_lr(int lr, unsigned int virtual_irq, > { > int maintenance_int = GICH_LR_MAINTENANCE_IRQ; > > - BUG_ON(lr > nr_lrs); > + BUG_ON(lr >= nr_lrs); > + BUG_ON(lr < 0);> + BUG_ON(state & ~(GICH_LR_STATE_MASK<<GICH_LR_STATE_SHIFT));This suggests that STATE_MASK is inconveniently defined, it''d be more normal to include the SHIFT in the mask. The same is true of all the other GICH_LR_*_MASK/SHIFT defines. The only one which is used is GICH_LR_VIRTUAL_MASK+SHIFT, and I guess I can see why in that case. Acked-by: Ian Campbell <ian.campbell@citrix.com> Ian.> > GICH[GICH_LR + lr] = state | > maintenance_int |
Ian Campbell
2013-Apr-29 14:57 UTC
Re: [RFC 02/29] xen/arm: don''t allow dom0 to access to vpl011 UART0 memory range
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> As vpl011 UART is not initialized for dom 0, when the domain tries to access to > this range, a segfault will occur in Xen. The right behaviour should be a data > abort for the guest. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com> However I wonder if the provision of a vpl011 UART isn''t something which should be made platform specific. It''s really a workaround for DEBUG_LL in a kernel which is configured for vexpress, I expect Arndale has different serial ports?> --- > xen/arch/arm/vpl011.c | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > > diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c > index 9472d0a..13ba623 100644 > --- a/xen/arch/arm/vpl011.c > +++ b/xen/arch/arm/vpl011.c > @@ -85,7 +85,9 @@ static void uart0_print_char(char c) > > static int uart0_mmio_check(struct vcpu *v, paddr_t addr) > { > - return addr >= UART0_START && addr < UART0_END; > + struct domain *d = v->domain; > + > + return d->domain_id != 0 && addr >= UART0_START && addr < UART0_END; > } > > static int uart0_mmio_read(struct vcpu *v, mmio_info_t *info)
Ian Campbell
2013-Apr-29 14:58 UTC
Re: [RFC 03/29] xen/arm: Remove duplicated GICD_ICPIDR2 definition
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>> --- > xen/include/asm-arm/gic.h | 1 - > 1 file changed, 1 deletion(-) > > diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h > index 47354dd..c3f87e1 100644 > --- a/xen/include/asm-arm/gic.h > +++ b/xen/include/asm-arm/gic.h > @@ -43,7 +43,6 @@ > #define GICD_ICFGRN (0xCFC/4) > #define GICD_NSACR (0xE00/4) > #define GICD_NSACRN (0xEFC/4) > -#define GICD_ICPIDR2 (0xFE8/4) > #define GICD_SGIR (0xF00/4) > #define GICD_CPENDSGIR (0xF10/4) > #define GICD_CPENDSGIRN (0xF1C/4)
Ian Campbell
2013-Apr-29 15:01 UTC
Re: [RFC 04/29] xen/arm: Bump early printk internal buffer to 512
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> When debug is enabled in device tree code, some lines > are bigger than 80 characters.I''m a little concerned about putting such a relatively large thing on the stack. Especially the initstack which I have a feeling is only 4K. We are single processor when early_printk is used, right? So a static __initdata buffer would also work?> > Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/early_printk.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c > index bdf4c0e..b21f572 100644 > --- a/xen/arch/arm/early_printk.c > +++ b/xen/arch/arm/early_printk.c > @@ -41,7 +41,7 @@ static void __init early_puts(const char *s) > > static void __init early_vprintk(const char *fmt, va_list args) > { > - char buf[80]; > + char buf[512]; > > vsnprintf(buf, sizeof(buf), fmt, args); > early_puts(buf);
Ian Campbell
2013-Apr-29 15:01 UTC
Re: [RFC 05/29] xen/arm: Fix early_panic when EARLY_PRINTK is disabled
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> Even if EARLY_PRINTK is not enabled, early_panic must never return. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>> --- > xen/include/asm-arm/early_printk.h | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/xen/include/asm-arm/early_printk.h b/xen/include/asm-arm/early_printk.h > index a770d4a..a0297a7 100644 > --- a/xen/include/asm-arm/early_printk.h > +++ b/xen/include/asm-arm/early_printk.h > @@ -20,7 +20,7 @@ void early_panic(const char *fmt, ...) __attribute__((noreturn)); > #else > > static inline void early_printk(const char *fmt, ...) {} > -static inline void early_panic(const char *fmt, ...) {} > +static inline void __attribute__((noreturn)) early_panic(const char *fmt, ...) {while(1);} > > #endif >
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> On some setup, the first linux page table is at 0x40004000. Xen will load > dom0 device tree at 0x4000100. In case of the device tree is big, linux will > corrupt the device tree.How big can a dtb be? To clash it'd need to be 15¾K?> Signed-off-by: Julien Grall <julien.grall@linaro.org>I suppose right after the kernel is as good as anywhere: Acked-by: Ian Campbell <ian.campbell@citrix.com>> --- > xen/arch/arm/domain_build.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > index 3f50193..ad0ab35 100644 > --- a/xen/arch/arm/domain_build.c > +++ b/xen/arch/arm/domain_build.c > @@ -407,8 +407,9 @@ int construct_dom0(struct domain *d) > /* The following loads use the domain's p2m */ > p2m_load_VTTBR(d); > > - dtb_load(&kinfo); > + kinfo.dtb_paddr = kinfo.zimage.load_addr + kinfo.zimage.len; > kernel_load(&kinfo); > + dtb_load(&kinfo); > > discard_initial_modules(); >_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Julien Grall
2013-Apr-29 15:13 UTC
Re: [RFC 01/29] xen/arm: lr must be included in range [0-nr_lr[
On 04/29/2013 03:55 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > > Typo in subject, [ at the end, did you mean ] or ) ? ( I can never > remember which one is inclusive)I mean ). But [ is also accepted even if it''s non-standard. http://mathworld.wolfram.com/OpenInterval.html I will fix it.>> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/arch/arm/gic.c | 4 +++- >> 1 file changed, 3 insertions(+), 1 deletion(-) >> >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c >> index bc8faf2..bac2af2 100644 >> --- a/xen/arch/arm/gic.c >> +++ b/xen/arch/arm/gic.c >> @@ -512,7 +512,9 @@ static inline void gic_set_lr(int lr, unsigned int virtual_irq, >> { >> int maintenance_int = GICH_LR_MAINTENANCE_IRQ; >> >> - BUG_ON(lr > nr_lrs); >> + BUG_ON(lr >= nr_lrs); >> + BUG_ON(lr < 0); > >> + BUG_ON(state & ~(GICH_LR_STATE_MASK<<GICH_LR_STATE_SHIFT)); > > This suggests that STATE_MASK is inconveniently defined, it''d be more > normal to include the SHIFT in the mask. > > The same is true of all the other GICH_LR_*_MASK/SHIFT defines. The only > one which is used is GICH_LR_VIRTUAL_MASK+SHIFT, and I guess I can see > why in that case. >I think all GICH_LR_*_MASK must be consistent. If we modify GICH_LR_STATE_* we need to modify all the others. This is basically the same for GICH_LR_PRIORITY_MASK/SHIFT but it''s seems we don''t use the mask. -- Julien
Julien Grall
2013-Apr-29 15:19 UTC
Re: [RFC 02/29] xen/arm: don''t allow dom0 to access to vpl011 UART0 memory range
On 04/29/2013 03:57 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> As vpl011 UART is not initialized for dom 0, when the domain tries to access to >> this range, a segfault will occur in Xen. The right behaviour should be a data >> abort for the guest. >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Acked-by: Ian Campbell <ian.campbell@citrix.com> > > However I wonder if the provision of a vpl011 UART isn''t something which > should be made platform specific. > > It''s really a workaround for DEBUG_LL in a kernel which is configured > for vexpress, I expect Arndale has different serial ports?Right. I''m currently working on a patch for linux to enable early printk for Arm. For the moment it''s doesn''t impact the Arndale board because this range is already mapped to a physical address. By the way, I think vpl011 is useless with Stefano''s patch series for SMP. He moved xenvm out of versatile express platform. -- Julien
Ian Campbell
2013-Apr-29 15:19 UTC
Re: [RFC 07/29] xen/arm: Create a hierarchical device tree
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> Add function to parse the device tree and create a hierarchical tree. > > This code is based on drivers/of/base.c in linux source.Do I understand correctly that most of the complex changes here are pre-existing Linux code imported into Xen? It informs how much review effort I will give it before I just give in and Ack it ;-)> + np = unflatten_dt_alloc(&mem, sizeof(struct dt_device_node) + allocl, > + __alignof__(struct dt_device_node)); > + if ( allnextpp ) > + { > + memset(np, 0, sizeof(*np)); > + np->full_name = ((char *)np) + sizeof(struct dt_device_node); > + /* By default dom0 owns the dom0 */Is the second dom0 supposed to be something else?> + np->used_by = 0;> +struct dt_property { > + const char *name; > + u32 length; > + void *value; > + struct dt_property *next; > +}; > + > +#define DT_USED_BY_XEN DOMID_INVALIDThere is already a DOMID_XEN which you could use. Ian.
Julien Grall
2013-Apr-29 15:22 UTC
Re: [RFC 04/29] xen/arm: Bump early printk internal buffer to 512
On 04/29/2013 04:01 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> When debug is enabled in device tree code, some lines >> are bigger than 80 characters. > > I''m a little concerned about putting such a relatively large thing on > the stack. Especially the initstack which I have a feeling is only 4K. > > We are single processor when early_printk is used, right? So a static > __initdata buffer would also work?Right. I will fix it in the next patch series. -- Julien
Ian Campbell
2013-Apr-29 15:23 UTC
Re: [RFC 08/29] xen/arm: Add helpers to use the device tree
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: Are these also from Linux?> Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/common/device_tree.c | 120 +++++++++++++++++++++++++++++++++++++++++ > xen/include/xen/device_tree.h | 120 +++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 240 insertions(+) > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > index 05285b7..dd4b813 100644 > --- a/xen/common/device_tree.c > +++ b/xen/common/device_tree.c > @@ -573,6 +573,54 @@ const void *dt_get_property(const struct dt_device_node *np, > return pp ? pp->value : NULL; > } > > +bool_t dt_device_is_compatible(const struct dt_device_node *device, > + const char *compat) > +{ > + const char* cp; > + u32 cplen, l; > + > + cp = dt_get_property(device, "compatible", &cplen); > + if ( cp == NULL ) > + return 0; > + while ( cplen > 0 ) > + { > + if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 )We have functions which do this already, don''t we? Also things like dt_node_cmp, dt_read_number etc have analogues in the current code. If these are from Linux I''m inclined to believe they will be better than our own. For 4.4 we should look at removing our variants. Or maybe if I keep reading the series I will find them going away already? Ian
Ian Campbell
2013-Apr-29 15:28 UTC
Re: [RFC 10/29] xen/arm: Add helpers to retrieve an interrupt description from the device tree
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h > index 7386358..42dc172 100644 > --- a/xen/include/xen/irq.h > +++ b/xen/include/xen/irq.h > @@ -33,6 +33,31 @@ struct irqaction { > #define NEVER_ASSIGN_IRQ (-2) > #define FREE_TO_ASSIGN_IRQ (-3) > > +/** > + * IRQ line type. > + * > + * IRQ_TYPE_NONE - default, unspecified type > + * IRQ_TYPE_EDGE_RISING - rising edge triggered > + * IRQ_TYPE_EDGE_FALLING - falling edge triggered > + * IRQ_TYPE_EDGE_BOTH - rising and falling edge triggered > + * IRQ_TYPE_LEVEL_HIGH - high level triggered > + * IRQ_TYPE_LEVEL_LOW - low level triggered > + * IRQ_TYPE_LEVEL_MASK - Mask to filter out the level bits > + * IRQ_TYPE_SENSE_MASK - Mask for all the above bits > + */ > +#define IRQ_TYPE_NONE 0x00000000 > +#define IRQ_TYPE_EDGE_RISING 0x00000001 > +#define IRQ_TYPE_EDGE_FALLING 0x00000002 > +#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) > +#define IRQ_TYPE_LEVEL_HIGH 0x00000004 > +#define IRQ_TYPE_LEVEL_LOW 0x00000008 > +#define IRQ_TYPE_LEVEL_MASK (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH) > +#define IRQ_TYPE_SENSE_MASK 0x0000000f > + > +/* If type == IRQ_TYPE_NONE, assume we use level triggered */ > +#define irq_is_level_trigger(irq) \ > + (((irq)->type & IRQ_TYPE_LEVEL_MASK) || ((irq)->type == IRQ_TYPE_NONE))What is the type of irq here? None of the structs in this irq.h have a type member, so I must be looking in the wrong place. Or is it struct dt_irq? If so then can we put these in a DT (or ARM) specific header and add a DT_ prefix, rather than pollute the non-DT headers, e.g. these defines have no meaning on x86 AFAICT. Ian.
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> This function routes an IRQ to a specific cpu. The IRQ is retrieved via > the device tree. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>> --- > xen/arch/arm/gic.c | 11 +++++++++++ > xen/include/asm-arm/gic.h | 5 +++++ > 2 files changed, 16 insertions(+) > > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c > index bac2af2..e03bb67 100644 > --- a/xen/arch/arm/gic.c > +++ b/xen/arch/arm/gic.c > @@ -238,6 +238,17 @@ static int gic_route_irq(unsigned int irq, bool_t level, > return 0; > } > > +/* Program the GIC to route an interrupt with a dt_irq */ > +void gic_route_dt_irq(const struct dt_irq *irq, unsigned int cpu_mask, > + unsigned int priority) > +{ > + bool_t level; > + > + level = irq_is_level_trigger(irq); > + > + gic_route_irq(irq->irq, level, cpu_mask, priority); > +} > + > static void __init gic_dist_init(void) > { > uint32_t type; > diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h > index c3f87e1..2fac673 100644 > --- a/xen/include/asm-arm/gic.h > +++ b/xen/include/asm-arm/gic.h > @@ -133,6 +133,8 @@ > #define VGIC_IRQ_EVTCHN_CALLBACK 31 > > #ifndef __ASSEMBLY__ > +#include <xen/device_tree.h> > + > extern int domain_vgic_init(struct domain *d); > extern void domain_vgic_free(struct domain *d); > > @@ -141,6 +143,9 @@ extern int vcpu_vgic_init(struct vcpu *v); > extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq,int virtual); > extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq); > > +/* Program the GIC to route an interrupt with a dt_irq */ > +extern void gic_route_dt_irq(const struct dt_irq *irq, unsigned int cpu_mask, > + unsigned int priority); > extern void gic_route_ppis(void); > extern void gic_route_spis(void); >
On 04/29/2013 04:07 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> On some setup, the first linux page table is at 0x40004000. Xen will load >> dom0 device tree at 0x4000100. In case of the device tree is big, linux will >> corrupt the device tree. > > How big can a dtb be? To clash it'd need to be 15¾K?I can't find a maximum size. The field is encoded on 32 bits. For instance the size of dtb is: - 12K for the versatile express - 20K for the Arndale board -- Julien _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> This function translates an interrupt specifier to an IRQ number and IRQ > type (ie: level trigger, edge trigger,...). It''s GIC specific. > > Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/gic.c | 20 ++++++++++++++++++++ > xen/arch/arm/setup.c | 1 + > xen/include/asm-arm/gic.h | 4 ++++ > 3 files changed, 25 insertions(+) > > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c > index e03bb67..1f44fea 100644 > --- a/xen/arch/arm/gic.c > +++ b/xen/arch/arm/gic.c > @@ -329,6 +329,26 @@ static void __cpuinit gic_hyp_disable(void) > GICH[GICH_HCR] = 0; > } > > +int gic_irq_xlate(const u32 *intspec, unsigned int intsize, > + unsigned int *out_hwirq, > + unsigned int *out_type) > +{ > + if ( intsize < 3 ) > + return -EINVAL; > + > + /* Get the interrupt number and add 16 to skip over SGIs */ > + *out_hwirq = intspec[1] + 16; > + > + /* For SPIs, we need to add 16 more to get the GIC irq ID number */ > + if ( !intspec[0] ) > + *out_hwirq += 16; > + > + if ( out_type ) > + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;These defines could replace the hardcoded 0xf08 in make_hypervisor_node? Super!> + > + return 0; > +} > + > /* Set up the GIC */ > void __init gic_init(void) > { > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index 77d0879..51f4bba 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -429,6 +429,7 @@ void __init start_xen(unsigned long boot_phys_offset, > setup_mm(fdt_paddr, fdt_size); > > dt_unflatten_host_device_tree(); > + dt_irq_xlate = gic_irq_xlate;It feels like this ought to belong in a gic_init function of some sort?> > #ifdef EARLY_UART_ADDRESS > /* TODO Need to get device tree or command line for UART address */ > diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h > index 2fac673..945e8db 100644 > --- a/xen/include/asm-arm/gic.h > +++ b/xen/include/asm-arm/gic.h > @@ -187,6 +187,10 @@ extern void send_SGI_allbutself(enum gic_sgi sgi); > /* print useful debug info */ > extern void gic_dump_info(struct vcpu *v); > > +/* IRQ translation function for the device tree */ > +int gic_irq_xlate(const u32 *intspec, unsigned int intsize, > + unsigned int *out_hwirq, unsigned int *out_type); > + > #endif /* __ASSEMBLY__ */ > #endif >
Julien Grall
2013-Apr-29 15:32 UTC
Re: [RFC 07/29] xen/arm: Create a hierarchical device tree
On 04/29/2013 04:19 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> Add function to parse the device tree and create a hierarchical tree. >> >> This code is based on drivers/of/base.c in linux source. > > Do I understand correctly that most of the complex changes here are > pre-existing Linux code imported into Xen? It informs how much review > effort I will give it before I just give in and Ack it ;-)Yes. It''s the same for patches 8, 9 and 10. I have just reindent the code and use xen internal functions.>> + np = unflatten_dt_alloc(&mem, sizeof(struct dt_device_node) + allocl, >> + __alignof__(struct dt_device_node)); >> + if ( allnextpp ) >> + { >> + memset(np, 0, sizeof(*np)); >> + np->full_name = ((char *)np) + sizeof(struct dt_device_node); >> + /* By default dom0 owns the dom0 */ > > Is the second dom0 supposed to be something else?it''s "device" :). I will fix it.>> + np->used_by = 0; > >> +struct dt_property { >> + const char *name; >> + u32 length; >> + void *value; >> + struct dt_property *next; >> +}; >> + >> +#define DT_USED_BY_XEN DOMID_INVALID > > There is already a DOMID_XEN which you could use. > > Ian. >
Ian Campbell
2013-Apr-29 15:35 UTC
Re: [RFC 13/29] xen/arm: Use hierarchical device tree to retrieve GIC information
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> - Remove early parsing for GIC addresses > - Remove hard coded maintenance IRQ numberAt last, the payoff!> > Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/gic.c | 63 ++++++++++++++++++++++++++++------------- > xen/common/device_tree.c | 42 ---------------------------I like this line!> @@ -464,7 +486,7 @@ void gic_route_ppis(void) > { > /* XXX should get these from DT */ > /* GIC maintenance */ > - gic_route_irq(25, 1, 1u << smp_processor_id(), 0xa0); > + gic_route_dt_irq(&gic.maintenance, 1u << smp_processor_id(), 0xa0); > /* Hypervisor Timer */ > gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0); > /* Virtual Timer */ > @@ -813,7 +835,8 @@ void gic_dump_info(struct vcpu *v) > > void __cpuinit init_maintenance_interrupt(void) > { > - request_irq(25, maintenance_interrupt, 0, "irq-maintenance", NULL); > + request_irq(gic.maintenance.irq, maintenance_interrupt, > + 0, "irq-maintenance", NULL);Would a dt_request_irq be useful anywhere other than here? Ian.
Ian Campbell
2013-Apr-29 15:38 UTC
Re: [RFC 14/29] xen/arm: Retrieve timer interrupts from the device tree
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> +/* List of timer''s IRQ */ > +enum ppi_nr > +{ > + PHYS_SECURE_PPI, > + PHYS_NONSECURE_PPI, > + VIRT_PPI, > + HYP_PPI, > + MAX_TIMER_PPI, > +}; > + > +static struct dt_irq timer_irq[MAX_TIMER_PPI]; > + > /*static inline*/ s_time_t ticks_to_ns(uint64_t ticks) > { > return muldiv64(ticks, SECONDS(1), 1000 * cpu_khz); > @@ -90,6 +103,28 @@ static uint32_t calibrate_timer(void) > /* Set up the timer on the boot CPU */ > int __init init_xen_time(void) > { > + struct dt_device_node *dev; > + int res; > + unsigned int i; > + > + dev = dt_find_compatible_node(NULL, NULL, "arm,armv7-timer"); > + if ( !dev ) > + panic("Unable to find a compatible timer in the device tree\n"); > + > + dt_device_set_used_by(dev, DT_USED_BY_XEN); > + > + /* Retrieve all IRQs for the timer */ > + for ( i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++ ) > + { > + res = dt_device_get_irq(dev, i, &timer_irq[i]);If you expect the PPI nrs to have specific values you should declare them as such in the enum. Ian.
Julien Grall
2013-Apr-29 15:40 UTC
Re: [RFC 08/29] xen/arm: Add helpers to use the device tree
On 04/29/2013 04:23 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > > Are these also from Linux? > >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/common/device_tree.c | 120 +++++++++++++++++++++++++++++++++++++++++ >> xen/include/xen/device_tree.h | 120 +++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 240 insertions(+) >> >> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c >> index 05285b7..dd4b813 100644 >> --- a/xen/common/device_tree.c >> +++ b/xen/common/device_tree.c >> @@ -573,6 +573,54 @@ const void *dt_get_property(const struct dt_device_node *np, >> return pp ? pp->value : NULL; >> } >> >> +bool_t dt_device_is_compatible(const struct dt_device_node *device, >> + const char *compat) >> +{ >> + const char* cp; >> + u32 cplen, l; >> + >> + cp = dt_get_property(device, "compatible", &cplen); >> + if ( cp == NULL ) >> + return 0; >> + while ( cplen > 0 ) >> + { >> + if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 ) > > We have functions which do this already, don''t we? Also things like > dt_node_cmp, dt_read_number etc have analogues in the current code. > > If these are from Linux I''m inclined to believe they will be better than > our own. For 4.4 we should look at removing our variants. > > Or maybe if I keep reading the series I will find them going away > already?In fact it''s exactly the same, except the current function deals with flat device tree and the new one deals with the hierarchical device tree. I''m afraid we can''t remove this duplicate code, we still need it for early scan of the device tree to retrieve memory, cpus, and modules informations. Once all the xen code moved to the new device tree API. This function will be static. -- Julien Grall
Ian Campbell
2013-Apr-29 15:41 UTC
Re: [RFC 15/29] xen/arm: Don''t hardcode VGIC informations
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> @@ -754,11 +759,21 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq) > > int gicv_setup(struct domain *d) > { > + /* TODO: Retrieve distributor and CPU guest base address from the > + * guest DTS > + * For the moment we use dom0 DTSFWIW I think what we will need here eventually is domctl''s so the toolstack can set this stuff explicitly to match the DT it generates, not to pass the guest DTB to the hypervisor and parse it or anything like that (maybe that''s not what you were suggesting).> /* Number of ranks of interrupt registers for a domain */ > @@ -79,7 +77,16 @@ int domain_vgic_init(struct domain *d) > int i; > > d->arch.vgic.ctlr = 0; > - d->arch.vgic.nr_lines = 32; > + > + /**Javadoc? ;-) Other than those two nits: Acked-by: Ian Campbell <ian.campbell@citrix.com>> + * Currently nr_lines in vgic and gic doesn''t have the same meanings > + * Here nr_lines = number of SPIs > + */ > + if ( d->domain_id == 0 ) > + d->arch.vgic.nr_lines = gic_number_lines() - 32; > + else > + d->arch.vgic.nr_lines = 0; /* We don''t need SPIs for the guest */ > +
Ian Campbell
2013-Apr-29 15:44 UTC
Re: [RFC 16/29] xen/arm: Introduce a generic way to use a device from the device tree
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S > index fd755d7..7434e83 100644 > --- a/xen/arch/arm/xen.lds.S > +++ b/xen/arch/arm/xen.lds.S > @@ -76,6 +76,12 @@ SECTIONS > __lock_profile_end = .; > #endif > > + .dev.info : {No ALIGNment requirement?> + _sdevice = .; > + *(.dev.info) > + _edevice = .; > + } :text > + > . = ALIGN(PAGE_SIZE); /* Init code and data */ > __init_begin = .; > .init.text : {
Julien Grall
2013-Apr-29 15:45 UTC
Re: [RFC 10/29] xen/arm: Add helpers to retrieve an interrupt description from the device tree
On 04/29/2013 04:28 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h >> index 7386358..42dc172 100644 >> --- a/xen/include/xen/irq.h >> +++ b/xen/include/xen/irq.h >> @@ -33,6 +33,31 @@ struct irqaction { >> #define NEVER_ASSIGN_IRQ (-2) >> #define FREE_TO_ASSIGN_IRQ (-3) >> >> +/** >> + * IRQ line type. >> + * >> + * IRQ_TYPE_NONE - default, unspecified type >> + * IRQ_TYPE_EDGE_RISING - rising edge triggered >> + * IRQ_TYPE_EDGE_FALLING - falling edge triggered >> + * IRQ_TYPE_EDGE_BOTH - rising and falling edge triggered >> + * IRQ_TYPE_LEVEL_HIGH - high level triggered >> + * IRQ_TYPE_LEVEL_LOW - low level triggered >> + * IRQ_TYPE_LEVEL_MASK - Mask to filter out the level bits >> + * IRQ_TYPE_SENSE_MASK - Mask for all the above bits >> + */ >> +#define IRQ_TYPE_NONE 0x00000000 >> +#define IRQ_TYPE_EDGE_RISING 0x00000001 >> +#define IRQ_TYPE_EDGE_FALLING 0x00000002 >> +#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) >> +#define IRQ_TYPE_LEVEL_HIGH 0x00000004 >> +#define IRQ_TYPE_LEVEL_LOW 0x00000008 >> +#define IRQ_TYPE_LEVEL_MASK (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH) >> +#define IRQ_TYPE_SENSE_MASK 0x0000000f >> + >> +/* If type == IRQ_TYPE_NONE, assume we use level triggered */ >> +#define irq_is_level_trigger(irq) \ >> + (((irq)->type & IRQ_TYPE_LEVEL_MASK) || ((irq)->type == IRQ_TYPE_NONE)) > > What is the type of irq here? None of the structs in this irq.h have a > type member, so I must be looking in the wrong place.It''s specified if an IRQ will be edge-triggered or level-triggered. Except the irq_is_level_trigger macro, all this code is copied from include/linux/irq.h in linux. That''s why I have put this code here.> Or is it struct dt_irq? If so then can we put these in a DT (or ARM)> specific header and add a DT_ prefix, rather than pollute the non-DT > headers, e.g. these defines have no meaning on x86 AFAICT.Yes. I will move to device_tree.h. -- Julien
Ian Campbell
2013-Apr-29 15:46 UTC
Re: [RFC 17/29] xen/arm: New callback in uart_driver to get device tree interrupt structure
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> The existing function serial_irq doesn''t allow to retrieve if the interrupt > is edge or level trigger. > > Use this function to route all serial IRQs to xen.All of them? At most we want the one Xen is using, don''t we?> Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/gic.c | 12 ++++++++++++ > xen/drivers/char/serial.c | 10 ++++++++++ > xen/include/xen/serial.h | 5 +++++ > 3 files changed, 27 insertions(+) > > diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c > index bf0c1fd..8085b6e 100644 > --- a/xen/arch/arm/gic.c > +++ b/xen/arch/arm/gic.c > @@ -24,6 +24,7 @@ > #include <xen/irq.h> > #include <xen/sched.h> > #include <xen/errno.h> > +#include <xen/serial.h> > #include <xen/softirq.h> > #include <xen/list.h> > #include <xen/device_tree.h> > @@ -497,9 +498,20 @@ void gic_route_ppis(void) > > void gic_route_spis(void) > { > + int seridx; > + const struct dt_irq *irq; > + > /* XXX should get these from DT */ > /* UART */ > gic_route_irq(37, 0, 1u << smp_processor_id(), 0xa0);Did you intend to remove this line?> + for ( seridx = 0; seridx <= SERHND_IDX; seridx++ ) > + { > + if ( (irq = serial_dt_irq(seridx)) == NULL ) > + continue; > + > + gic_route_dt_irq(irq, 1u << smp_processor_id(), 0xa0); > + } > } > > void __init release_irq(unsigned int irq) > diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c > index a3d2b26..0ae7e4d 100644 > --- a/xen/drivers/char/serial.c > +++ b/xen/drivers/char/serial.c > @@ -482,6 +482,16 @@ int __init serial_irq(int idx) > return -1; > } > > +const struct dt_irq __init *serial_dt_irq(int idx) > +{ > + if ( (idx >= 0) && (idx < ARRAY_SIZE(com)) && > + com[idx].driver && com[idx].driver->dt_irq_get ) > + return com[idx].driver->dt_irq_get(&com[idx]); > + > + return NULL; > +} > + > + > void serial_suspend(void) > { > int i; > diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h > index b932ed4..5de5171 100644 > --- a/xen/include/xen/serial.h > +++ b/xen/include/xen/serial.h > @@ -71,6 +71,8 @@ struct uart_driver { > int (*getc)(struct serial_port *, char *); > /* Get IRQ number for this port''s serial line: returns -1 if none. */ > int (*irq)(struct serial_port *); > + /* Get IRQ device node for this port''s serial line: returns NULL if none. */ > + const struct dt_irq *(*dt_irq_get)(struct serial_port *); > }; > > /* ''Serial handles'' are composed from the following fields. */ > @@ -120,6 +122,9 @@ void serial_end_log_everything(int handle); > /* Return irq number for specified serial port (identified by index). */ > int serial_irq(int idx); > > +/* Return irq device node for specified serial port (identified by index). */ > +const struct dt_irq *serial_dt_irq(int idx); > + > /* Serial suspend/resume. */ > void serial_suspend(void); > void serial_resume(void);
Ian Campbell
2013-Apr-29 15:51 UTC
Re: [RFC 18/29] xen/arm: add generic UART to get the device in the device tree
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> This generic UART will find the right UART via xen command line > with com1=myserial. > > "myserial" is the alias of the UART in the device tree. Xen will retrieve > the information via the device tree and call the initialization function for > this specific UART thanks to the device API. > > Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/setup.c | 3 +- > xen/drivers/char/Makefile | 1 + > xen/drivers/char/arm-uart.c | 76 +++++++++++++++++++++++++++++++++++++++++++ > xen/include/xen/serial.h | 8 +++++ > 4 files changed, 87 insertions(+), 1 deletion(-) > create mode 100644 xen/drivers/char/arm-uart.c > > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index 51f4bba..e5d8724 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -434,8 +434,9 @@ void __init start_xen(unsigned long boot_phys_offset, > #ifdef EARLY_UART_ADDRESS > /* TODO Need to get device tree or command line for UART address */ > pl011_init(0, FIXMAP_ADDR(FIXMAP_CONSOLE)); > - console_init_preirq(); > #endif > + arm_uart_init(); > + console_init_preirq(); > > /* FIXME: Do something smarter */ > dt_switch_to_printk(); > diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile > index ab2246d..e68a54a 100644 > --- a/xen/drivers/char/Makefile > +++ b/xen/drivers/char/Makefile > @@ -2,4 +2,5 @@ obj-y += console.o > obj-$(HAS_NS16550) += ns16550.o > obj-$(HAS_PL011) += pl011.o > obj-$(HAS_EHCI) += ehci-dbgp.o > +obj-$(CONFIG_ARM) += arm-uart.o > obj-y += serial.o > diff --git a/xen/drivers/char/arm-uart.c b/xen/drivers/char/arm-uart.c > new file mode 100644 > index 0000000..e242ae2 > --- /dev/null > +++ b/xen/drivers/char/arm-uart.c > @@ -0,0 +1,76 @@ > +/* > + * xen/drivers/char/arm-uart.c > + * > + * Generic ARM uart retrieved via the device tree > + * > + * Julien Grall <julien.grall@linaro.org> > + * Copyright (c) 2013 Linaro Limited. > + * > + * 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. > + */ > + > +#include <asm/device.h> > +#include <asm/early_printk.h> > +#include <asm/types.h> > +#include <xen/console.h> > +#include <xen/device_tree.h> > +#include <xen/mm.h> > +#include <xen/serial.h> > + > +/* > + * Configure serial port with string: devname > + * Where devname is the alias of the device in the device tree > + */ > +static char __initdata opt_com1[30] = ""; > +string_param("com1", opt_com1);com1 is a bit of an x86-ism. Can we use e.g. uart0 or does common code constrain us here? Better would be to arrange things such that console=myserial does the lookup. Then myserial=<foo> sets options for that device. I think you would need to add a call to dt_console_init to console_init_preirq(), in the "Where should console output go?" loop. Ian.
On 04/29/2013 04:31 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> This function translates an interrupt specifier to an IRQ number and IRQ >> type (ie: level trigger, edge trigger,...). It''s GIC specific. >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/arch/arm/gic.c | 20 ++++++++++++++++++++ >> xen/arch/arm/setup.c | 1 + >> xen/include/asm-arm/gic.h | 4 ++++ >> 3 files changed, 25 insertions(+) >> >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c >> index e03bb67..1f44fea 100644 >> --- a/xen/arch/arm/gic.c >> +++ b/xen/arch/arm/gic.c >> @@ -329,6 +329,26 @@ static void __cpuinit gic_hyp_disable(void) >> GICH[GICH_HCR] = 0; >> } >> >> +int gic_irq_xlate(const u32 *intspec, unsigned int intsize, >> + unsigned int *out_hwirq, >> + unsigned int *out_type) >> +{ >> + if ( intsize < 3 ) >> + return -EINVAL; >> + >> + /* Get the interrupt number and add 16 to skip over SGIs */ >> + *out_hwirq = intspec[1] + 16; >> + >> + /* For SPIs, we need to add 16 more to get the GIC irq ID number */ >> + if ( !intspec[0] ) >> + *out_hwirq += 16; >> + >> + if ( out_type ) >> + *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK; > > These defines could replace the hardcoded 0xf08 in make_hypervisor_node? > Super!Right.>> + >> + return 0; >> +} >> + >> /* Set up the GIC */ >> void __init gic_init(void) >> { >> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c >> index 77d0879..51f4bba 100644 >> --- a/xen/arch/arm/setup.c >> +++ b/xen/arch/arm/setup.c >> @@ -429,6 +429,7 @@ void __init start_xen(unsigned long boot_phys_offset, >> setup_mm(fdt_paddr, fdt_size); >> >> dt_unflatten_host_device_tree(); >> + dt_irq_xlate = gic_irq_xlate; > > It feels like this ought to belong in a gic_init function of some sort?The device tree needs this function to translate interrupt for the UART driver. The GIC is initialized too late (few lines after serial setup). Is there a drawback to move gic initialization before the serial setup? The only one I have found is we must use early printk in the function. So most of the time the user can''t see the output, assuming he doesn''t compile Xen with CONFIG_EARLY_PRINTK. -- Julien Grall
Ian Campbell
2013-Apr-29 15:54 UTC
Re: [RFC 19/29] xen/arm: Use device tree API in pl011 UART driver
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> -/* TODO: Parse UART config from device-tree or command-line */I think the "or command-line" bit of this comment remains? Otherwise: Acked-by: Ian Campbell <ian.campbell@citrix.com>
Ian Campbell
2013-Apr-29 15:59 UTC
Re: [RFC 20/29] xen/arm: Use the device tree to map the address range and IRQ to dom0
> @@ -30,6 +31,14 @@ static void __init parse_dom0_mem(const char *s) > } > custom_param("dom0_mem", parse_dom0_mem); > > +#define DEBUG_DTDid you mean to leave this on by default? Seems like it might be a bit verbose? On the otherhand it would be nice to replace the "Map CS2 MMIO regions 1:1 in the P2M ..." messages with something, and this seems like it...> + > +static int parse_device_tree(struct domain *d)This is more like map_device_from_device_tree(d). Both minor nits, so: Acked-by: Ian Campbell <ian.campbell@citrix.com>
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:> Hello, > > This patch series is divided in 4 parts: > - Patch 1-6: Minor bug fixes > - Patch 7-10: Add hierarchical device tree support based on linux tree > - Patch 11-24: Remove harcoded part > - Patch 25-28: Arndale support based on Anthony''s git > > Xen can boot on both Arndale Board and the Versatile Express without > recompilation. But there is still some hardcoded part, mainly in assembly. > > Things to do: > - Move secondary CPUs bring up code in platform specific > - Move out of Xen the switch between secure mode and hypervisor mode > - Rework dom0 device tree creation > - Use everywhere the new device tree API > - Add a support for SYS MMU > > If you want to try this patch series you can clone: > git clone -b arm git://xenbits.xen.org/people/julieng/xen-unstable.gitFrom the wiki it seems that this also requires a non-mainline kernel (a linaro derived thing?). How close is arndale support to being upstream/mainline? Ian.
Ian Campbell
2013-Apr-29 16:13 UTC
Re: [RFC 21/29] xen/arm: WORKAROUND 1:1 memory mapping for dom0
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> Currently xen doesn''t implement SYS MMU. When a device will talk with dom0 > with DMA request the domain will use GFN instead of MFN. > For instance on the arndale board, without this patch the network doesn''t > work.Yes :-/ Pragmatically I think we are better off with this short term hack than without support for the Arndale, but it''s not terribly satisfactory. If there were any other platforms available I''d say that we should pick a platform for which the IOMMU docs were more easily forthcoming than they have proven to be on this platform. I''m slightly worried that we may get stuck with this hack. Perhaps we should say, prominently, that this hack will go away in 4.4 and that platforms which have not been converted to an IOMMU will not be supported from 4.4 onwards and that, yes, this could include the arndale unless docs and/or a vendor written driver appear. Of course we may end up eating crow if all the other platforms have the same problem, since we clearly can''t remove support for all platforms...> The 1:1 mapping is a workaround and MUST be remove as soon as a SYS MMU is > implemented in XEN.I wonder if we can make this conditional on a suitable board level DT compat node ("samsung,arndale" or "samsung,exynos5250" perhaps)? And print a big warning when enabling it of course.> Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/domain_build.c | 51 ++++++++++++++++++++++++------------------- > xen/arch/arm/kernel.h | 1 - > 2 files changed, 28 insertions(+), 24 deletions(-) > > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > index ced73a7..11298e1 100644 > --- a/xen/arch/arm/domain_build.c > +++ b/xen/arch/arm/domain_build.c > @@ -66,29 +66,36 @@ static int set_memory_reg(struct domain *d, struct kernel_info *kinfo, > int address_cells, int size_cells, u32 *new_cell) > { > int reg_size = (address_cells + size_cells) * sizeof(*cell); > - int l = 0; > - u64 start; > - u64 size; > + paddr_t start; > + paddr_t size; > + struct page_info *pg; > + unsigned int order = get_order_from_bytes(dom0_mem); > + int res; > + paddr_t spfn; > > - while ( kinfo->unassigned_mem > 0 && l + reg_size <= len > - && kinfo->mem.nr_banks < NR_MEM_BANKS ) > - { > - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); > - if ( size > kinfo->unassigned_mem ) > - size = kinfo->unassigned_mem; > - device_tree_set_reg(&new_cell, address_cells, size_cells, start, size); > - > - printk("Populate P2M %#"PRIx64"->%#"PRIx64"\n", start, start + size); > - p2m_populate_ram(d, start, start + size); > - kinfo->mem.bank[kinfo->mem.nr_banks].start = start; > - kinfo->mem.bank[kinfo->mem.nr_banks].size = size; > - kinfo->mem.nr_banks++; > - kinfo->unassigned_mem -= size; > - > - l += reg_size; > - } > + pg = alloc_domheap_pages(d, order, 0); > + if ( !pg ) > + panic("Failed to allocate contiguous memory for dom0\n");Interesting, so we don''t actually need RAM to start at the same place as the real hardware would have it and the kernel copes? Slight surprising the kernel didn''t whine, but OK!> + spfn = page_to_mfn(pg); > + start = spfn << PAGE_SHIFT; > + size = (1 << order) << PAGE_SHIFT; > + > + // 1:1 mapping > + printk("Populate P2M %#"PRIx64"->%#"PRIx64" (1:1 mapping for dom0)\n", > + start, start + size); > + res = guest_physmap_add_page(d, spfn, spfn, order); > > - return l; > + if ( res ) > + panic("Unable to add pages in DOM0: %d\n", res); > + > + device_tree_set_reg(&new_cell, address_cells, size_cells, start, size); > + > + kinfo->mem.bank[0].start = start; > + kinfo->mem.bank[0].size = size; > + kinfo->mem.nr_banks = 1; > + > + return reg_size; > } > > static int write_properties(struct domain *d, struct kernel_info *kinfo, > @@ -434,8 +441,6 @@ static int prepare_dtb(struct domain *d, struct kernel_info *kinfo) > int new_size; > int ret; > > - kinfo->unassigned_mem = dom0_mem; > - > fdt = device_tree_flattened; > > new_size = fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE; > diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h > index 1776a4d..687f6c4 100644 > --- a/xen/arch/arm/kernel.h > +++ b/xen/arch/arm/kernel.h > @@ -15,7 +15,6 @@ struct kernel_info { > #endif > > void *fdt; /* flat device tree */ > - paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */ > struct dt_mem_info mem; > > paddr_t dtb_paddr;
Ian Campbell
2013-Apr-29 16:15 UTC
Re: [RFC 22/29] xen/arm: Allow Xen to run on multiple platform without recompilation
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> Xen can include various platform support (ie: exynos5, versatile express...) > and choose during boot time a set of callbacks for the current board. > These callbacks will be called in places where each board can have specific > code. For the moment the callbacks are: > - platform_init: additional initialization for the platform > - platform_init_time: some platform (ie: Exynos 5) needs to initialize > the timer with an uncommon way > - platform_specific_mapping: add mapping to dom0 which are not specified > in the device tree > - platform_reset: reset the platform > > Signed-off-by: Julien Grall <julien.grall@linaro.org>alignment in xen.lds.S again, otherwise: Acked-by: Ian Campbell <ian.campbell@citrix.com>
Ian Campbell
2013-Apr-29 16:27 UTC
Re: [RFC 23/29] xen/arm: Add versatile express platform
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> This platform contains nearly nothing specific except the reset function. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>> +/* Board-specific: base address of system controller */ > +#define SP810_ADDRESS 0x1C020000Even better would be if this is in DT. Ian.
Julien Grall
2013-Apr-29 16:30 UTC
Re: [RFC 13/29] xen/arm: Use hierarchical device tree to retrieve GIC information
On 04/29/2013 04:35 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> - Remove early parsing for GIC addresses >> - Remove hard coded maintenance IRQ number > > At last, the payoff! > >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/arch/arm/gic.c | 63 ++++++++++++++++++++++++++++------------- >> xen/common/device_tree.c | 42 --------------------------- > > I like this line! > >> @@ -464,7 +486,7 @@ void gic_route_ppis(void) >> { >> /* XXX should get these from DT */ >> /* GIC maintenance */ >> - gic_route_irq(25, 1, 1u << smp_processor_id(), 0xa0); >> + gic_route_dt_irq(&gic.maintenance, 1u << smp_processor_id(), 0xa0); >> /* Hypervisor Timer */ >> gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0); >> /* Virtual Timer */ >> @@ -813,7 +835,8 @@ void gic_dump_info(struct vcpu *v) >> >> void __cpuinit init_maintenance_interrupt(void) >> { >> - request_irq(25, maintenance_interrupt, 0, "irq-maintenance", NULL); >> + request_irq(gic.maintenance.irq, maintenance_interrupt, >> + 0, "irq-maintenance", NULL); > > Would a dt_request_irq be useful anywhere other than here? >Yes. Nearly everywhere the IRQ is retrieved from the device tree (ie: UART, timer...). I will create dt_request_irq. -- Julien
Julien Grall
2013-Apr-29 16:42 UTC
Re: [RFC 15/29] xen/arm: Don''t hardcode VGIC informations
On 04/29/2013 04:41 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> @@ -754,11 +759,21 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq) >> >> int gicv_setup(struct domain *d) >> { >> + /* TODO: Retrieve distributor and CPU guest base address from the >> + * guest DTS >> + * For the moment we use dom0 DTS > > FWIW I think what we will need here eventually is domctl''s so the > toolstack can set this stuff explicitly to match the DT it generates, > not to pass the guest DTB to the hypervisor and parse it or anything > like that (maybe that''s not what you were suggesting).I don''t have a particular plan for parsing/generate the guest DTB. We can: 1) Replace the GIC base address in the guest DTB 2) Use the GIC base address found in the DTB I would prefer the second solution, and use the first when the node doesn''t exist. I believe the guest DTB is currently appended to the kernel. So do we really need to create a new hypercall for this purpose? We can add some logic in the toolstack to take the kernel and the device tree in arguments and concatenate it.>> /* Number of ranks of interrupt registers for a domain */ >> @@ -79,7 +77,16 @@ int domain_vgic_init(struct domain *d) >> int i; >> >> d->arch.vgic.ctlr = 0; >> - d->arch.vgic.nr_lines = 32; >> + >> + /** > > Javadoc? ;-)Right. Bad habit :). I will replace by /*. -- Julien
Ian Campbell
2013-Apr-29 16:45 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> Add CONFIG_EARLY_PRINTK options in configs/arm{32,64}.mk to let the user > to choose if he wants to have early output, ie before the console is initialized.These shouldn''t go in config/arm*.mk but should be handed in xen/arch/arm/> > This code is specific for each UART. When CONFIG_EARLY_PRINTK is enabled, > Xen will only be able to run on a board with this UART. > > If a developper wants to add support for a new UART, he must implement the > following function/variable: > - early_uart_paddr: variable which contains the physical base address > for the UART > - early_uart_init: initialize the UART > - early_uart_ready: check and wait until the UART can transmit a new > character > - early_uart_transmit: transmit a character > > For more details about the parameters of each function, > see arm{32,64}/debug-pl011.S comments.It''s a damned shame the asm isn''t compatible, oh well...> diff --git a/config/arm32.mk b/config/arm32.mk > index f64f0c1..83a7767 100644 > --- a/config/arm32.mk > +++ b/config/arm32.mk > @@ -7,6 +7,17 @@ CONFIG_ARM_$(XEN_OS) := y > # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: > CFLAGS += -marm > > +# Xen early debugging function > +# This is helpful if you are debbuging code that executes before the console > +# is initialized. > +# Note that selecting this option will limit Xen to a single UART > +# definition. Attempting to boot Xen image on a different platform *will > +# not work*, so this option should not be enable for Xens that are > +# intended to be portable. > +# Possible value: > +# - none: no early printkBlank/unset would represent none? Or you mean literal "none"?> +# - pl011: printk with PL011 UART > +CONFIG_EARLY_PRINTK := noneI guess you mean literal none... Can this be overriden on command line or in .config? You may need to use ?= so it can be.> HAS_PL011 := y > > # Use only if calling $(LD) directly. > diff --git a/config/arm64.mk b/config/arm64.mk > index b2457eb..6187df8 100644 > --- a/config/arm64.mk > +++ b/config/arm64.mk > @@ -4,6 +4,17 @@ CONFIG_ARM_$(XEN_OS) := y > > CFLAGS += #-marm -march= -mcpu= etc > > +# Xen early debugging function > +# This is helpful if you are debbuging code that executes before the console > +# is initialized. > +# Note that selecting this option will limit Xen to a single UART > +# definition. Attempting to boot Xen image on a different platform *will > +# not work*, so this option should not be enable for Xens that are > +# intended to be portable. > +# Possible value: > +# - none: no early printk > +# - pl011: printk with PL011 UART > +CONFIG_EARLY_PRINTK := noneShall we create config/arm.mk, included from arm32 and arm64 and reduce the duplication?> diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile > index 1ad3364..6af8ca3 100644 > --- a/xen/arch/arm/arm32/Makefile > +++ b/xen/arch/arm/arm32/Makefile > @@ -5,4 +5,7 @@ obj-y += mode_switch.o > obj-y += proc-ca15.o > > obj-y += traps.o > -obj-y += domain.o > \ No newline at end of file > +obj-y += domain.o > + > +obj-$(EARLY_PRINTK) += debug.o > +obj-$(CONFIG_EARLY_PL011) += debug-pl011.oThis could become obj-$(EARLY_PRINTK) += debug-$(CONFIG_EARLY_PRINTK).o and save adding a new one for each name? And if you create a stub debug-none.S you could just make it obj-y ? Should we gate this on debug=y?> @@ -106,8 +106,10 @@ past_zImage: > bne 1b > > boot_cpu: > -#ifdef EARLY_UART_ADDRESS > - ldr r11, =EARLY_UART_ADDRESS /* r11 := UART base address */ > +#ifdef EARLY_PRINTK > + ldr r0, =early_uart_paddr /* VA of early_uart_paddr */ > + add r0, r0, r10 /* PA of early_uart_paddr */ > + ldr r11, [r0] /* r11 := UART base address */If head.S were to #include debug-pl011.inc would that simplify some of this stuff? Ian.
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> Signed-off-by: Julien Grall <julien.grall@linaro.org>WIthout a datasheet there isn''t much review to be done,> --- > config/arm32.mk | 1 + > xen/drivers/char/Makefile | 1 + > xen/drivers/char/exynos5-uart.c | 346 +++++++++++++++++++++++++++++++++++++++ > 3 files changed, 348 insertions(+) > create mode 100644 xen/drivers/char/exynos5-uart.c > > diff --git a/config/arm32.mk b/config/arm32.mk > index 83a7767..593a1d1 100644 > --- a/config/arm32.mk > +++ b/config/arm32.mk > @@ -19,6 +19,7 @@ CFLAGS += -marm > # - pl011: printk with PL011 UART > CONFIG_EARLY_PRINTK := none > HAS_PL011 := y > +HAS_EXYNOS5 := y > > # Use only if calling $(LD) directly. > #LDFLAGS_DIRECT_OpenBSD = _obsd > diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile > index e68a54a..12a4b49 100644 > --- a/xen/drivers/char/Makefile > +++ b/xen/drivers/char/Makefile > @@ -1,6 +1,7 @@ > obj-y += console.o > obj-$(HAS_NS16550) += ns16550.o > obj-$(HAS_PL011) += pl011.o > +obj-$(HAS_EXYNOS5) += exynos5-uart.o > obj-$(HAS_EHCI) += ehci-dbgp.o > obj-$(CONFIG_ARM) += arm-uart.o > obj-y += serial.o > diff --git a/xen/drivers/char/exynos5-uart.c b/xen/drivers/char/exynos5-uart.c > new file mode 100644 > index 0000000..1bae153 > --- /dev/null > +++ b/xen/drivers/char/exynos5-uart.c > @@ -0,0 +1,346 @@ > +/* > + * xen/drivers/char/exynos5-uart.c > + * > + * Driver for Exynos 4210 UART. > + * > + * Anthony PERARD <anthony.perard@citrix.com> > + * Copyright (c) 2012 Citrix Systems. > + * > + * 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. > + */ > + > +#include <xen/config.h> > +#include <xen/console.h> > +#include <xen/errno.h> > +#include <xen/serial.h> > +#include <xen/init.h> > +#include <xen/irq.h> > +#include <asm/early_printk.h> > +#include <asm/device.h> > + > +static struct exynos5_uart { > + unsigned int baud, clock_hz, data_bits, parity, stop_bits; > + struct dt_irq irq; > + volatile uint32_t *regs; > + struct irqaction irqaction; > +} exynos5_com[2] = {{0}}; > + > +/* register addresses */ > +#define ULCON (0x00/4) > +#define UCON (0x04/4) > +#define UFCON (0x08/4) > +#define UMCON (0x0c/4) > +#define UTRSTAT (0x10/4) > +#define UERSTAT (0x14/4) > +#define UFSTAT (0x18/4) > +#define UMSTAT (0x1c/4) > +#define UTXH (0x20/4) > +#define URXH (0x24/4) > +#define UBRDIV (0x28/4) > +#define UFRACVAL (0x2c/4) > +#define UINTP (0x30/4) > +#define UINTS (0x34/4) > +#define UINTM (0x38/4) > + > +/* ULCON */ > +#define RXIRQ (0x1<<0) > +#define RXDMA (0x2<<0) > +#define TXIRQ (0x1<<2) > +#define TXDMA (0x2<<2) > + > +/* UFCON */ > +#define FIFO_TX_RESET (1<<2) > +#define FIFO_RX_RESET (1<<1) > +#define FIFO_EN (1<<0) > + > +/* UMCON */ > +#define INT_EN (1<<3) > + > +/* UTRSTAT */ > +#define TXE (1<<2) > +#define TXFE (1<<1) > +#define RXDR (1<<0) > + > +/* Interrupt bits (UINTP, UINTS, UINTM) */ > +#define MODEM (1<<3) > +#define TXD (1<<2) > +#define ERROR (1<<1) > +#define RXD (1<<0) > +#define ALLI (MODEM|TXD|ERROR|RXD) > + > +/* These parity settings can be ORed directly into the ULCON. */ > +#define PARITY_NONE (0) > +#define PARITY_ODD (0x4) > +#define PARITY_EVEN (0x5) > +#define FORCED_CHECKED_AS_ONE (0x6) > +#define FORCED_CHECKED_AS_ZERO (0x7) > + > +static void exynos5_uart_interrupt(int irq, void *data, struct cpu_user_regs *regs) > +{ > + struct serial_port *port = data; > + struct exynos5_uart *uart = port->uart; > + unsigned int status = uart->regs[UINTP]; > + > + if ( status ) > + { > + do > + { > + // clear all pending interrept > + // but should take care of ERROR and MODEMXen comments are always /* */ I think. A bunch of instance of this in this patch.> + > + if ( status & ERROR ) > + { > + int error_bit = uart->regs[UERSTAT] & 0xf; > + if ( error_bit & (1 << 0) ) > + printk(XENLOG_ERR "uart: overrun error\n"); > + if ( error_bit & (1 << 1) ) > + printk(XENLOG_ERR "uart: parity error\n"); > + if ( error_bit & (1 << 2) ) > + printk(XENLOG_ERR "uart: frame error\n"); > + if ( error_bit & (1 << 3) )Can you #define these bits? [...]> + // reset FIFO_TX_RESET | FIFO_RX_RESET | > + uart->regs[UFCON] = (0x6 << 8) | FIFO_EN;#define> + > + /* Enable the UART for RX and TX */ > + // level tx/rx interrupt,only rx > + // enable rx timeout interrupt > + uart->regs[UCON] = (0 << 9) | (0 << 8) | RXIRQ | TXIRQ | ( 1 << 7);More #defines, I expect there''s a bunch more too ;-)> +} > + > +static void __init exynos5_uart_init_postirq(struct serial_port *port) > +{ > + struct exynos5_uart *uart = port->uart; > + int rc; > + > + if ( uart->irq.irq > 0 ) > + { > + uart->irqaction.handler = exynos5_uart_interrupt; > + uart->irqaction.name = "exynos5_uart"; > + uart->irqaction.dev_id = port; > + if ( (rc = setup_irq(uart->irq.irq, &uart->irqaction)) != 0 ) > + printk("ERROR: Failed to allocate exynos5_uart IRQ %d\n", > + uart->irq.irq); > + > + /* Unmask interrupts */ > + uart->regs[UINTM] = 0; //MODEM|TXD|ERROR; // only have rx interruptLeft over debug? Ian.
Ian Campbell
2013-Apr-29 16:55 UTC
Re: [RFC 08/29] xen/arm: Add helpers to use the device tree
On Mon, 2013-04-29 at 16:40 +0100, Julien Grall wrote:> On 04/29/2013 04:23 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > > > > Are these also from Linux? > > > >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > >> --- > >> xen/common/device_tree.c | 120 +++++++++++++++++++++++++++++++++++++++++ > >> xen/include/xen/device_tree.h | 120 +++++++++++++++++++++++++++++++++++++++++ > >> 2 files changed, 240 insertions(+) > >> > >> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > >> index 05285b7..dd4b813 100644 > >> --- a/xen/common/device_tree.c > >> +++ b/xen/common/device_tree.c > >> @@ -573,6 +573,54 @@ const void *dt_get_property(const struct dt_device_node *np, > >> return pp ? pp->value : NULL; > >> } > >> > >> +bool_t dt_device_is_compatible(const struct dt_device_node *device, > >> + const char *compat) > >> +{ > >> + const char* cp; > >> + u32 cplen, l; > >> + > >> + cp = dt_get_property(device, "compatible", &cplen); > >> + if ( cp == NULL ) > >> + return 0; > >> + while ( cplen > 0 ) > >> + { > >> + if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 ) > > > > We have functions which do this already, don''t we? Also things like > > dt_node_cmp, dt_read_number etc have analogues in the current code. > > > > If these are from Linux I''m inclined to believe they will be better than > > our own. For 4.4 we should look at removing our variants. > > > > Or maybe if I keep reading the series I will find them going away > > already? > > > In fact it''s exactly the same, except the current function deals with > flat device tree and the new one deals with the hierarchical device tree. > > I''m afraid we can''t remove this duplicate code, we still need it for > early scan of the device tree to retrieve memory, cpus, and modules > informations.We can''t use dt_compat_cmp in the early code?> > Once all the xen code moved to the new device tree API. This function > will be static. >
Ian Campbell
2013-Apr-29 16:56 UTC
Re: [RFC 10/29] xen/arm: Add helpers to retrieve an interrupt description from the device tree
On Mon, 2013-04-29 at 16:45 +0100, Julien Grall wrote:> On 04/29/2013 04:28 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > >> diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h > >> index 7386358..42dc172 100644 > >> --- a/xen/include/xen/irq.h > >> +++ b/xen/include/xen/irq.h > >> @@ -33,6 +33,31 @@ struct irqaction { > >> #define NEVER_ASSIGN_IRQ (-2) > >> #define FREE_TO_ASSIGN_IRQ (-3) > >> > >> +/** > >> + * IRQ line type. > >> + * > >> + * IRQ_TYPE_NONE - default, unspecified type > >> + * IRQ_TYPE_EDGE_RISING - rising edge triggered > >> + * IRQ_TYPE_EDGE_FALLING - falling edge triggered > >> + * IRQ_TYPE_EDGE_BOTH - rising and falling edge triggered > >> + * IRQ_TYPE_LEVEL_HIGH - high level triggered > >> + * IRQ_TYPE_LEVEL_LOW - low level triggered > >> + * IRQ_TYPE_LEVEL_MASK - Mask to filter out the level bits > >> + * IRQ_TYPE_SENSE_MASK - Mask for all the above bits > >> + */ > >> +#define IRQ_TYPE_NONE 0x00000000 > >> +#define IRQ_TYPE_EDGE_RISING 0x00000001 > >> +#define IRQ_TYPE_EDGE_FALLING 0x00000002 > >> +#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) > >> +#define IRQ_TYPE_LEVEL_HIGH 0x00000004 > >> +#define IRQ_TYPE_LEVEL_LOW 0x00000008 > >> +#define IRQ_TYPE_LEVEL_MASK (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH) > >> +#define IRQ_TYPE_SENSE_MASK 0x0000000f > >> + > >> +/* If type == IRQ_TYPE_NONE, assume we use level triggered */ > >> +#define irq_is_level_trigger(irq) \ > >> + (((irq)->type & IRQ_TYPE_LEVEL_MASK) || ((irq)->type == IRQ_TYPE_NONE)) > > > > What is the type of irq here? None of the structs in this irq.h have a > > type member, so I must be looking in the wrong place. > > It''s specified if an IRQ will be edge-triggered or level-triggered.Sorry, I meant the type of the irq argument (as in which kind of struct). That was pretty ambiguous though!> Except the irq_is_level_trigger macro, all this code is copied from > include/linux/irq.h in linux. That''s why I have put this code here. > > > Or is it struct dt_irq? If so then can we put these in a DT (or ARM) > > > specific header and add a DT_ prefix, rather than pollute the non-DT > > headers, e.g. these defines have no meaning on x86 AFAICT. > > > Yes. I will move to device_tree.h. >
Julien Grall
2013-Apr-29 16:58 UTC
Re: [RFC 16/29] xen/arm: Introduce a generic way to use a device from the device tree
On 04/29/2013 04:44 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S >> index fd755d7..7434e83 100644 >> --- a/xen/arch/arm/xen.lds.S >> +++ b/xen/arch/arm/xen.lds.S >> @@ -76,6 +76,12 @@ SECTIONS >> __lock_profile_end = .; >> #endif >> >> + .dev.info : { > > No ALIGNment requirement?I don''t think so. I can add ALIGN(8) to be sure. -- Julien
Julien Grall
2013-Apr-29 17:09 UTC
Re: [RFC 17/29] xen/arm: New callback in uart_driver to get device tree interrupt structure
On 04/29/2013 04:46 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> The existing function serial_irq doesn''t allow to retrieve if the interrupt >> is edge or level trigger. >> >> Use this function to route all serial IRQs to xen. > > All of them? At most we want the one Xen is using, don''t we?My comment is a bit confusing. "all serial IRQs" means all IRQs of UART registered via serial_register_uart. Currently Xen on Arm can register zero one one UART (com1).>> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/arch/arm/gic.c | 12 ++++++++++++ >> xen/drivers/char/serial.c | 10 ++++++++++ >> xen/include/xen/serial.h | 5 +++++ >> 3 files changed, 27 insertions(+) >> >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c >> index bf0c1fd..8085b6e 100644 >> --- a/xen/arch/arm/gic.c >> +++ b/xen/arch/arm/gic.c >> @@ -24,6 +24,7 @@ >> #include <xen/irq.h> >> #include <xen/sched.h> >> #include <xen/errno.h> >> +#include <xen/serial.h> >> #include <xen/softirq.h> >> #include <xen/list.h> >> #include <xen/device_tree.h> >> @@ -497,9 +498,20 @@ void gic_route_ppis(void) >> >> void gic_route_spis(void) >> { >> + int seridx; >> + const struct dt_irq *irq; >> + >> /* XXX should get these from DT */ >> /* UART */ >> gic_route_irq(37, 0, 1u << smp_processor_id(), 0xa0); > > Did you intend to remove this line?Yes, I let this line to avoid to break xen boot on versatile express. -- Julien
Julien Grall
2013-Apr-29 17:24 UTC
Re: [RFC 18/29] xen/arm: add generic UART to get the device in the device tree
On 04/29/2013 04:51 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> This generic UART will find the right UART via xen command line >> with com1=myserial. >> >> "myserial" is the alias of the UART in the device tree. Xen will retrieve >> the information via the device tree and call the initialization function for >> this specific UART thanks to the device API. >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/arch/arm/setup.c | 3 +- >> xen/drivers/char/Makefile | 1 + >> xen/drivers/char/arm-uart.c | 76 +++++++++++++++++++++++++++++++++++++++++++ >> xen/include/xen/serial.h | 8 +++++ >> 4 files changed, 87 insertions(+), 1 deletion(-) >> create mode 100644 xen/drivers/char/arm-uart.c >> >> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c >> index 51f4bba..e5d8724 100644 >> --- a/xen/arch/arm/setup.c >> +++ b/xen/arch/arm/setup.c >> @@ -434,8 +434,9 @@ void __init start_xen(unsigned long boot_phys_offset, >> #ifdef EARLY_UART_ADDRESS >> /* TODO Need to get device tree or command line for UART address */ >> pl011_init(0, FIXMAP_ADDR(FIXMAP_CONSOLE)); >> - console_init_preirq(); >> #endif >> + arm_uart_init(); >> + console_init_preirq(); >> >> /* FIXME: Do something smarter */ >> dt_switch_to_printk(); >> diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile >> index ab2246d..e68a54a 100644 >> --- a/xen/drivers/char/Makefile >> +++ b/xen/drivers/char/Makefile >> @@ -2,4 +2,5 @@ obj-y += console.o >> obj-$(HAS_NS16550) += ns16550.o >> obj-$(HAS_PL011) += pl011.o >> obj-$(HAS_EHCI) += ehci-dbgp.o >> +obj-$(CONFIG_ARM) += arm-uart.o >> obj-y += serial.o >> diff --git a/xen/drivers/char/arm-uart.c b/xen/drivers/char/arm-uart.c >> new file mode 100644 >> index 0000000..e242ae2 >> --- /dev/null >> +++ b/xen/drivers/char/arm-uart.c >> @@ -0,0 +1,76 @@ >> +/* >> + * xen/drivers/char/arm-uart.c >> + * >> + * Generic ARM uart retrieved via the device tree >> + * >> + * Julien Grall <julien.grall@linaro.org> >> + * Copyright (c) 2013 Linaro Limited. >> + * >> + * 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. >> + */ >> + >> +#include <asm/device.h> >> +#include <asm/early_printk.h> >> +#include <asm/types.h> >> +#include <xen/console.h> >> +#include <xen/device_tree.h> >> +#include <xen/mm.h> >> +#include <xen/serial.h> >> + >> +/* >> + * Configure serial port with string: devname >> + * Where devname is the alias of the device in the device tree >> + */ >> +static char __initdata opt_com1[30] = ""; >> +string_param("com1", opt_com1); > > com1 is a bit of an x86-ism. Can we use e.g. uart0 or does common code > constrain us here?>> Better would be to arrange things such that console=myserial does the > lookup. Then myserial=<foo> sets options for that device. > > I think you would need to add a call to dt_console_init to > console_init_preirq(), in the "Where should console output go?" loop.I don''t see an easy solution with dt_console_init. serial_parse_handle hardcodes the name of the serial, which only supports com1, com2, dbgp. Sadly, the serial initialization is made in the same function. If I understand your suggestion, you suggest to use console=myserial where *myserial* is the alias on the DTB, right? In this case the name could clash with the hardcoded ones in Xen that is not good. -- Julien
Julien Grall
2013-Apr-29 17:27 UTC
Re: [RFC 19/29] xen/arm: Use device tree API in pl011 UART driver
On 04/29/2013 04:54 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > >> -/* TODO: Parse UART config from device-tree or command-line */ > > I think the "or command-line" bit of this comment remains?Right. I will fix it. -- Julien
Julien Grall
2013-Apr-29 17:30 UTC
Re: [RFC 20/29] xen/arm: Use the device tree to map the address range and IRQ to dom0
On 04/29/2013 04:59 PM, Ian Campbell wrote:>> @@ -30,6 +31,14 @@ static void __init parse_dom0_mem(const char *s) >> } >> custom_param("dom0_mem", parse_dom0_mem); >> >> +#define DEBUG_DT > > Did you mean to leave this on by default? Seems like it might be a bit > verbose? On the otherhand it would be nice to replace the "Map CS2 MMIO > regions 1:1 in the P2M ..." messages with something, and this seems like > it...No. I forgot to comment this line. I will fix it.>> + >> +static int parse_device_tree(struct domain *d) > > This is more like map_device_from_device_tree(d).I will rename the function.> Both minor nits, so: > Acked-by: Ian Campbell <ian.campbell@citrix.com> >-- Julien
Julien Grall
2013-Apr-29 17:43 UTC
Re: [RFC 21/29] xen/arm: WORKAROUND 1:1 memory mapping for dom0
On 04/29/2013 05:13 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> Currently xen doesn''t implement SYS MMU. When a device will talk with dom0 >> with DMA request the domain will use GFN instead of MFN. >> For instance on the arndale board, without this patch the network doesn''t >> work. > > Yes :-/ Pragmatically I think we are better off with this short term > hack than without support for the Arndale, but it''s not terribly > satisfactory. If there were any other platforms available I''d say that > we should pick a platform for which the IOMMU docs were more easily > forthcoming than they have proven to be on this platform. > > I''m slightly worried that we may get stuck with this hack. Perhaps we > should say, prominently, that this hack will go away in 4.4 and that > platforms which have not been converted to an IOMMU will not be > supported from 4.4 onwards and that, yes, this could include the arndale > unless docs and/or a vendor written driver appear. > > Of course we may end up eating crow if all the other platforms have the > same problem, since we clearly can''t remove support for all platforms... > >> The 1:1 mapping is a workaround and MUST be remove as soon as a SYS MMU is >> implemented in XEN. > > I wonder if we can make this conditional on a suitable board level DT > compat node ("samsung,arndale" or "samsung,exynos5250" perhaps)? And > print a big warning when enabling it of course.What do you think about adding a workaround field in platform structure? It will contains PLATFORM_WORKAROUND_DOM0_11_MAPPING and perhaps other workaround if we really need it... This could avoid to check DT compat node for each platform where Xen need to do a 1:1 mapping for dom0.>> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/arch/arm/domain_build.c | 51 ++++++++++++++++++++++++------------------- >> xen/arch/arm/kernel.h | 1 - >> 2 files changed, 28 insertions(+), 24 deletions(-) >> >> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c >> index ced73a7..11298e1 100644 >> --- a/xen/arch/arm/domain_build.c >> +++ b/xen/arch/arm/domain_build.c >> @@ -66,29 +66,36 @@ static int set_memory_reg(struct domain *d, struct kernel_info *kinfo, >> int address_cells, int size_cells, u32 *new_cell) >> { >> int reg_size = (address_cells + size_cells) * sizeof(*cell); >> - int l = 0; >> - u64 start; >> - u64 size; >> + paddr_t start; >> + paddr_t size; >> + struct page_info *pg; >> + unsigned int order = get_order_from_bytes(dom0_mem); >> + int res; >> + paddr_t spfn; >> >> - while ( kinfo->unassigned_mem > 0 && l + reg_size <= len >> - && kinfo->mem.nr_banks < NR_MEM_BANKS ) >> - { >> - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); >> - if ( size > kinfo->unassigned_mem ) >> - size = kinfo->unassigned_mem; >> - device_tree_set_reg(&new_cell, address_cells, size_cells, start, size); >> - >> - printk("Populate P2M %#"PRIx64"->%#"PRIx64"\n", start, start + size); >> - p2m_populate_ram(d, start, start + size); >> - kinfo->mem.bank[kinfo->mem.nr_banks].start = start; >> - kinfo->mem.bank[kinfo->mem.nr_banks].size = size; >> - kinfo->mem.nr_banks++; >> - kinfo->unassigned_mem -= size; >> - >> - l += reg_size; >> - } >> + pg = alloc_domheap_pages(d, order, 0); >> + if ( !pg ) >> + panic("Failed to allocate contiguous memory for dom0\n"); > > Interesting, so we don''t actually need RAM to start at the same place as > the real hardware would have it and the kernel copes? Slight surprising > the kernel didn''t whine, but OK!I didn''t see specific warning from the kernel. Why the kernel should whine if the memory banks have changed? -- Julien
Julien Grall
2013-Apr-29 17:44 UTC
Re: [RFC 22/29] xen/arm: Allow Xen to run on multiple platform without recompilation
On 04/29/2013 05:15 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> Xen can include various platform support (ie: exynos5, versatile express...) >> and choose during boot time a set of callbacks for the current board. >> These callbacks will be called in places where each board can have specific >> code. For the moment the callbacks are: >> - platform_init: additional initialization for the platform >> - platform_init_time: some platform (ie: Exynos 5) needs to initialize >> the timer with an uncommon way >> - platform_specific_mapping: add mapping to dom0 which are not specified >> in the device tree >> - platform_reset: reset the platform >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > alignment in xen.lds.S again, otherwise:I will fix with ALIGN(8).> Acked-by: Ian Campbell <ian.campbell@citrix.com> > > >-- Julien
Julien Grall
2013-Apr-29 17:52 UTC
Re: [RFC 23/29] xen/arm: Add versatile express platform
On 04/29/2013 05:27 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> This platform contains nearly nothing specific except the reset function. >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Acked-by: Ian Campbell <ian.campbell@citrix.com> > >> +/* Board-specific: base address of system controller */ >> +#define SP810_ADDRESS 0x1C020000 > > Even better would be if this is in DT.It seems there is an *arm,vexpress-reset* node in the device tree. It needs some work, so I will send a separate patch to add support for the vexpress-reset function. -- Julien
Julien Grall
2013-Apr-29 18:12 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On 04/29/2013 05:45 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> Add CONFIG_EARLY_PRINTK options in configs/arm{32,64}.mk to let the user >> to choose if he wants to have early output, ie before the console is initialized. > > These shouldn''t go in config/arm*.mk but should be handed in > xen/arch/arm/I don''t understand why, it''s a config option and the user can modify arm32.mk>> >> This code is specific for each UART. When CONFIG_EARLY_PRINTK is enabled, >> Xen will only be able to run on a board with this UART. >> >> If a developper wants to add support for a new UART, he must implement the >> following function/variable: >> - early_uart_paddr: variable which contains the physical base address >> for the UART >> - early_uart_init: initialize the UART >> - early_uart_ready: check and wait until the UART can transmit a new >> character >> - early_uart_transmit: transmit a character >> >> For more details about the parameters of each function, >> see arm{32,64}/debug-pl011.S comments. > > It''s a damned shame the asm isn''t compatible, oh well... > >> diff --git a/config/arm32.mk b/config/arm32.mk >> index f64f0c1..83a7767 100644 >> --- a/config/arm32.mk >> +++ b/config/arm32.mk >> @@ -7,6 +7,17 @@ CONFIG_ARM_$(XEN_OS) := y >> # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: >> CFLAGS += -marm >> >> +# Xen early debugging function >> +# This is helpful if you are debbuging code that executes before the console >> +# is initialized. >> +# Note that selecting this option will limit Xen to a single UART >> +# definition. Attempting to boot Xen image on a different platform *will >> +# not work*, so this option should not be enable for Xens that are >> +# intended to be portable. >> +# Possible value: >> +# - none: no early printk > > Blank/unset would represent none? Or you mean literal "none"?I choose to use literal "none", but finally I think it''s better to have blank/unset.>> +# - pl011: printk with PL011 UART >> +CONFIG_EARLY_PRINTK := none > > I guess you mean literal none... > > Can this be overriden on command line or in .config? You may need to > use ?= so it can be.Yes. Make overrides all "local" variables with the ones on the command line.>> HAS_PL011 := y >> >> # Use only if calling $(LD) directly. >> diff --git a/config/arm64.mk b/config/arm64.mk >> index b2457eb..6187df8 100644 >> --- a/config/arm64.mk >> +++ b/config/arm64.mk >> @@ -4,6 +4,17 @@ CONFIG_ARM_$(XEN_OS) := y >> >> CFLAGS += #-marm -march= -mcpu= etc >> >> +# Xen early debugging function >> +# This is helpful if you are debbuging code that executes before the console >> +# is initialized. >> +# Note that selecting this option will limit Xen to a single UART >> +# definition. Attempting to boot Xen image on a different platform *will >> +# not work*, so this option should not be enable for Xens that are >> +# intended to be portable. >> +# Possible value: >> +# - none: no early printk >> +# - pl011: printk with PL011 UART >> +CONFIG_EARLY_PRINTK := none > > Shall we create config/arm.mk, included from arm32 and arm64 and reduce > the duplication?I think so.>> diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile >> index 1ad3364..6af8ca3 100644 >> --- a/xen/arch/arm/arm32/Makefile >> +++ b/xen/arch/arm/arm32/Makefile >> @@ -5,4 +5,7 @@ obj-y += mode_switch.o >> obj-y += proc-ca15.o >> >> obj-y += traps.o >> -obj-y += domain.o >> \ No newline at end of file >> +obj-y += domain.o >> + >> +obj-$(EARLY_PRINTK) += debug.o >> +obj-$(CONFIG_EARLY_PL011) += debug-pl011.o > > This could become > obj-$(EARLY_PRINTK) += debug-$(CONFIG_EARLY_PRINTK).o > and save adding a new one for each name? And if you create a stub > debug-none.S you could just make it obj-y ? Should we gate this on > debug=y?What does debug=y do? I think we don''t need debug-none.S if CONFIG_EARLY_PRINTK is unset when early printk is disabled. We just need to check in Rules.mk is CONFIG_EARLY_PRINTK is set or not and defined EARLY_PRINTK.>> @@ -106,8 +106,10 @@ past_zImage: >> bne 1b >> >> boot_cpu: >> -#ifdef EARLY_UART_ADDRESS >> - ldr r11, =EARLY_UART_ADDRESS /* r11 := UART base address */ >> +#ifdef EARLY_PRINTK >> + ldr r0, =early_uart_paddr /* VA of early_uart_paddr */ >> + add r0, r0, r10 /* PA of early_uart_paddr */ >> + ldr r11, [r0] /* r11 := UART base address */ > > If head.S were to #include debug-pl011.inc would that simplify some of > this stuff?It''s also used in debug.s, which is a wrapper for the C early printk. If we use macros instead of functions the code will be simplified. All link register used will be removed. I will rework this patch. -- Julien
Anthony PERARD
2013-Apr-29 18:12 UTC
Re: [RFC 25/29] xen/arm: Add exynos 4210 UART support
On 29/04/13 17:51, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> Signed-off-by: Julien Grall <julien.grall@linaro.org>Julien, could you add my signed off before yours?> WIthout a datasheet there isn''t much review to be done,You can find the datasheet in the "Exynos 5 Dual User Manual (Public) REV1.00.pdf" document. Hope it''s enough to have the name. -- Anthony PERARD
On 04/29/2013 05:13 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> Hello, >> >> This patch series is divided in 4 parts: >> - Patch 1-6: Minor bug fixes >> - Patch 7-10: Add hierarchical device tree support based on linux tree >> - Patch 11-24: Remove harcoded part >> - Patch 25-28: Arndale support based on Anthony''s git >> >> Xen can boot on both Arndale Board and the Versatile Express without >> recompilation. But there is still some hardcoded part, mainly in assembly. >> >> Things to do: >> - Move secondary CPUs bring up code in platform specific >> - Move out of Xen the switch between secure mode and hypervisor mode >> - Rework dom0 device tree creation >> - Use everywhere the new device tree API >> - Add a support for SYS MMU >> >> If you want to try this patch series you can clone: >> git clone -b arm git://xenbits.xen.org/people/julieng/xen-unstable.git > > From the wiki it seems that this also requires a non-mainline kernel (a > linaro derived thing?). How close is arndale support to being > upstream/mainline?The wiki page point to a linux 3.7 whit linaro patches and xen patches. It''s seems the Arndale support is nearly completed on 3.9. It''s a matter of about ten patches. I would prefer to stick on linaro tree to avoid to maintain our own Linux Arndale tree. We can switch to a linux upstream once the Arndale is fully supported. -- Julien
On 04/29/2013 07:12 PM, Anthony PERARD wrote:> On 29/04/13 17:51, Ian Campbell wrote: >> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >>> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Julien, could you add my signed off before yours?Yes. I will add to the next patch series. -- Julien
Julien Grall
2013-Apr-29 18:23 UTC
Re: [RFC 08/29] xen/arm: Add helpers to use the device tree
On 04/29/2013 05:55 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 16:40 +0100, Julien Grall wrote: >> On 04/29/2013 04:23 PM, Ian Campbell wrote: >> >>> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >>> >>> Are these also from Linux? >>> >>>> Signed-off-by: Julien Grall <julien.grall@linaro.org> >>>> --- >>>> xen/common/device_tree.c | 120 +++++++++++++++++++++++++++++++++++++++++ >>>> xen/include/xen/device_tree.h | 120 +++++++++++++++++++++++++++++++++++++++++ >>>> 2 files changed, 240 insertions(+) >>>> >>>> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c >>>> index 05285b7..dd4b813 100644 >>>> --- a/xen/common/device_tree.c >>>> +++ b/xen/common/device_tree.c >>>> @@ -573,6 +573,54 @@ const void *dt_get_property(const struct dt_device_node *np, >>>> return pp ? pp->value : NULL; >>>> } >>>> >>>> +bool_t dt_device_is_compatible(const struct dt_device_node *device, >>>> + const char *compat) >>>> +{ >>>> + const char* cp; >>>> + u32 cplen, l; >>>> + >>>> + cp = dt_get_property(device, "compatible", &cplen); >>>> + if ( cp == NULL ) >>>> + return 0; >>>> + while ( cplen > 0 ) >>>> + { >>>> + if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 ) >>> >>> We have functions which do this already, don''t we? Also things like >>> dt_node_cmp, dt_read_number etc have analogues in the current code. >>> >>> If these are from Linux I''m inclined to believe they will be better than >>> our own. For 4.4 we should look at removing our variants. >>> >>> Or maybe if I keep reading the series I will find them going away >>> already? >> >> >> In fact it''s exactly the same, except the current function deals with >> flat device tree and the new one deals with the hierarchical device tree. >> >> I''m afraid we can''t remove this duplicate code, we still need it for >> early scan of the device tree to retrieve memory, cpus, and modules >> informations. > > We can''t use dt_compat_cmp in the early code?Oh right, I though you were talking about dt_device_is_compatible and device_tree_node_compatible. -- Julien
Julien Grall
2013-Apr-29 20:23 UTC
Re: [RFC 14/29] xen/arm: Retrieve timer interrupts from the device tree
On 04/29/2013 04:38 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > >> +/* List of timer''s IRQ */ >> +enum ppi_nr >> +{ >> + PHYS_SECURE_PPI, >> + PHYS_NONSECURE_PPI, >> + VIRT_PPI, >> + HYP_PPI, >> + MAX_TIMER_PPI, >> +}; >> + >> +static struct dt_irq timer_irq[MAX_TIMER_PPI]; >> + >> /*static inline*/ s_time_t ticks_to_ns(uint64_t ticks) >> { >> return muldiv64(ticks, SECONDS(1), 1000 * cpu_khz); >> @@ -90,6 +103,28 @@ static uint32_t calibrate_timer(void) >> /* Set up the timer on the boot CPU */ >> int __init init_xen_time(void) >> { >> + struct dt_device_node *dev; >> + int res; >> + unsigned int i; >> + >> + dev = dt_find_compatible_node(NULL, NULL, "arm,armv7-timer"); >> + if ( !dev ) >> + panic("Unable to find a compatible timer in the device tree\n"); >> + >> + dt_device_set_used_by(dev, DT_USED_BY_XEN); >> + >> + /* Retrieve all IRQs for the timer */ >> + for ( i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++ ) >> + { >> + res = dt_device_get_irq(dev, i, &timer_irq[i]); > > If you expect the PPI nrs to have specific values you should declare > them as such in the enum.Right. I will fix it on the next patch series. -- Julien
Julien Grall
2013-Apr-29 20:42 UTC
Re: [RFC 13/29] xen/arm: Use hierarchical device tree to retrieve GIC information
On 04/29/2013 04:35 PM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >> - Remove early parsing for GIC addresses >> - Remove hard coded maintenance IRQ number > > At last, the payoff! > >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/arch/arm/gic.c | 63 ++++++++++++++++++++++++++++------------- >> xen/common/device_tree.c | 42 --------------------------- > > I like this line! > >> @@ -464,7 +486,7 @@ void gic_route_ppis(void) >> { >> /* XXX should get these from DT */ >> /* GIC maintenance */ >> - gic_route_irq(25, 1, 1u << smp_processor_id(), 0xa0); >> + gic_route_dt_irq(&gic.maintenance, 1u << smp_processor_id(), 0xa0); >> /* Hypervisor Timer */ >> gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0); >> /* Virtual Timer */ >> @@ -813,7 +835,8 @@ void gic_dump_info(struct vcpu *v) >> >> void __cpuinit init_maintenance_interrupt(void) >> { >> - request_irq(25, maintenance_interrupt, 0, "irq-maintenance", NULL); >> + request_irq(gic.maintenance.irq, maintenance_interrupt, >> + 0, "irq-maintenance", NULL); > > Would a dt_request_irq be useful anywhere other than here?As all the interrupts should be retrieved from the device_tree could we remove request_irq for ARM (ie move request_irq definition to asm-x86/irq.h)? It''s also a safe guard for developper to avoid hardcoded IRQ. Then we can: 1) modify irq argument type 2) rename the function in request_dt_irq I''m not sure the latter is usefull. -- Julien
Ian Campbell
2013-Apr-30 09:00 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> diff --git a/config/arm32.mk b/config/arm32.mk > index f64f0c1..83a7767 100644 > --- a/config/arm32.mk > +++ b/config/arm32.mk > @@ -7,6 +7,17 @@ CONFIG_ARM_$(XEN_OS) := y > # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb: > CFLAGS += -marm > > +# Xen early debugging function > +# This is helpful if you are debbuging code that executes before the console > +# is initialized. > +# Note that selecting this option will limit Xen to a single UART > +# definition. Attempting to boot Xen image on a different platform *will > +# not work*, so this option should not be enable for Xens that are > +# intended to be portable. > +# Possible value: > +# - none: no early printk > +# - pl011: printk with PL011 UART > +CONFIG_EARLY_PRINTK := noneI''m wondering if this is the right place for this "config", other than the load address (which is also arguably not supposed to be here), they are mostly per-platform variables rather than user focussed config options. This new option seems more akin to the debug=y or CONFIG_DTB_FILE buildtime options, which are mostly contained xen/Makefile and xen/arch/arm/Makefile etc. I''m not really sure about this though -- the hypervisor doesn''t really have much in the way of user tunable CONFIG options -- anyone else have any opinions?
Ian Campbell
2013-Apr-30 09:03 UTC
Re: [RFC 15/29] xen/arm: Don''t hardcode VGIC informations
On Mon, 2013-04-29 at 17:42 +0100, Julien Grall wrote:> On 04/29/2013 04:41 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > >> @@ -754,11 +759,21 @@ void gic_interrupt(struct cpu_user_regs *regs, int is_fiq) > >> > >> int gicv_setup(struct domain *d) > >> { > >> + /* TODO: Retrieve distributor and CPU guest base address from the > >> + * guest DTS > >> + * For the moment we use dom0 DTS > > > > FWIW I think what we will need here eventually is domctl''s so the > > toolstack can set this stuff explicitly to match the DT it generates, > > not to pass the guest DTB to the hypervisor and parse it or anything > > like that (maybe that''s not what you were suggesting). > > I don''t have a particular plan for parsing/generate the guest DTB. > We can: > 1) Replace the GIC base address in the guest DTB > 2) Use the GIC base address found in the DTB > > I would prefer the second solution, and use the first when the node > doesn''t exist.Use the second -- yes. Use the first when the node doesn''t exist -- no, the tools should ensure it always exists.> I believe the guest DTB is currently appended to the kernel. So do we > really need to create a new hypercall for this purpose? > We can add some logic in the toolstack to take the kernel and the device > tree in arguments and concatenate it.We cannot rely on CONFIG_ARM_APPEND_DTB long term, eventually the toolstack needs to generate the DTB corresponding to the guest configuration and supply it to the kernel through the appropriate register. In any case regardless of whether the guest DTB is appended or in a register we do not want the hypervisor to have to parse the guest DTB.> >> /* Number of ranks of interrupt registers for a domain */ > >> @@ -79,7 +77,16 @@ int domain_vgic_init(struct domain *d) > >> int i; > >> > >> d->arch.vgic.ctlr = 0; > >> - d->arch.vgic.nr_lines = 32; > >> + > >> + /** > > > > Javadoc? ;-) > > > Right. Bad habit :). I will replace by /*. >
Ian Campbell
2013-Apr-30 09:05 UTC
Re: [RFC 17/29] xen/arm: New callback in uart_driver to get device tree interrupt structure
On Mon, 2013-04-29 at 18:09 +0100, Julien Grall wrote:> On 04/29/2013 04:46 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > >> The existing function serial_irq doesn''t allow to retrieve if the interrupt > >> is edge or level trigger. > >> > >> Use this function to route all serial IRQs to xen. > > > > All of them? At most we want the one Xen is using, don''t we? > > My comment is a bit confusing. "all serial IRQs" means all IRQs of UART > registered via serial_register_uart. > > Currently Xen on Arm can register zero one one UART (com1).Ah, OK, thanks. "Use this function to route IRQs for all serial ports which Xen is using to Xen" ???> >> Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>> >> gic_route_irq(37, 0, 1u << smp_processor_id(), 0xa0); > > > > Did you intend to remove this line? > > Yes, I let this line to avoid to break xen boot on versatile express.I think I saw it get removed in a later patch dealing with vexpress, so that''s ok. Ian.
Ian Campbell
2013-Apr-30 09:09 UTC
Re: [RFC 18/29] xen/arm: add generic UART to get the device in the device tree
On Mon, 2013-04-29 at 18:24 +0100, Julien Grall wrote:> On 04/29/2013 04:51 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > >> This generic UART will find the right UART via xen command line > >> with com1=myserial. > >> > >> "myserial" is the alias of the UART in the device tree. Xen will retrieve > >> the information via the device tree and call the initialization function for > >> this specific UART thanks to the device API. > >> > >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > >> --- > >> xen/arch/arm/setup.c | 3 +- > >> xen/drivers/char/Makefile | 1 + > >> xen/drivers/char/arm-uart.c | 76 +++++++++++++++++++++++++++++++++++++++++++ > >> xen/include/xen/serial.h | 8 +++++ > >> 4 files changed, 87 insertions(+), 1 deletion(-) > >> create mode 100644 xen/drivers/char/arm-uart.c > >> > >> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > >> index 51f4bba..e5d8724 100644 > >> --- a/xen/arch/arm/setup.c > >> +++ b/xen/arch/arm/setup.c > >> @@ -434,8 +434,9 @@ void __init start_xen(unsigned long boot_phys_offset, > >> #ifdef EARLY_UART_ADDRESS > >> /* TODO Need to get device tree or command line for UART address */ > >> pl011_init(0, FIXMAP_ADDR(FIXMAP_CONSOLE)); > >> - console_init_preirq(); > >> #endif > >> + arm_uart_init(); > >> + console_init_preirq(); > >> > >> /* FIXME: Do something smarter */ > >> dt_switch_to_printk(); > >> diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile > >> index ab2246d..e68a54a 100644 > >> --- a/xen/drivers/char/Makefile > >> +++ b/xen/drivers/char/Makefile > >> @@ -2,4 +2,5 @@ obj-y += console.o > >> obj-$(HAS_NS16550) += ns16550.o > >> obj-$(HAS_PL011) += pl011.o > >> obj-$(HAS_EHCI) += ehci-dbgp.o > >> +obj-$(CONFIG_ARM) += arm-uart.o > >> obj-y += serial.o > >> diff --git a/xen/drivers/char/arm-uart.c b/xen/drivers/char/arm-uart.c > >> new file mode 100644 > >> index 0000000..e242ae2 > >> --- /dev/null > >> +++ b/xen/drivers/char/arm-uart.c > >> @@ -0,0 +1,76 @@ > >> +/* > >> + * xen/drivers/char/arm-uart.c > >> + * > >> + * Generic ARM uart retrieved via the device tree > >> + * > >> + * Julien Grall <julien.grall@linaro.org> > >> + * Copyright (c) 2013 Linaro Limited. > >> + * > >> + * 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. > >> + */ > >> + > >> +#include <asm/device.h> > >> +#include <asm/early_printk.h> > >> +#include <asm/types.h> > >> +#include <xen/console.h> > >> +#include <xen/device_tree.h> > >> +#include <xen/mm.h> > >> +#include <xen/serial.h> > >> + > >> +/* > >> + * Configure serial port with string: devname > >> + * Where devname is the alias of the device in the device tree > >> + */ > >> +static char __initdata opt_com1[30] = ""; > >> +string_param("com1", opt_com1); > > > > com1 is a bit of an x86-ism. Can we use e.g. uart0 or does common code > > constrain us here? > > > > > > Better would be to arrange things such that console=myserial does the > > lookup. Then myserial=<foo> sets options for that device. > > > > I think you would need to add a call to dt_console_init to > > console_init_preirq(), in the "Where should console output go?" loop. > > > I don''t see an easy solution with dt_console_init. > serial_parse_handle hardcodes the name of the serial, which only > supports com1, com2, dbgp. Sadly, the serial initialization is made in > the same function.Couldn''t it also hardcode a call to a "is this a dt serial alias" function?> If I understand your suggestion, you suggest to use console=myserial > where *myserial* is the alias on the DTB, right?Right.> In this case the name could clash with the hardcoded ones in Xen that is not good.console=dt:<alias> ? Or to be honest I''m not sure that having the dt aliases shadow the Xen hardcoded ones would be a bad thing -- the x86 centric com<X> definition hardcoded in Xen is hardly likely to be useful on ARM or any DT using platform. Ian.
Ian Campbell
2013-Apr-30 09:12 UTC
Re: [RFC 21/29] xen/arm: WORKAROUND 1:1 memory mapping for dom0
On Mon, 2013-04-29 at 18:43 +0100, Julien Grall wrote:> On 04/29/2013 05:13 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > >> Currently xen doesn''t implement SYS MMU. When a device will talk with dom0 > >> with DMA request the domain will use GFN instead of MFN. > >> For instance on the arndale board, without this patch the network doesn''t > >> work. > > > > Yes :-/ Pragmatically I think we are better off with this short term > > hack than without support for the Arndale, but it''s not terribly > > satisfactory. If there were any other platforms available I''d say that > > we should pick a platform for which the IOMMU docs were more easily > > forthcoming than they have proven to be on this platform. > > > > I''m slightly worried that we may get stuck with this hack. Perhaps we > > should say, prominently, that this hack will go away in 4.4 and that > > platforms which have not been converted to an IOMMU will not be > > supported from 4.4 onwards and that, yes, this could include the arndale > > unless docs and/or a vendor written driver appear. > > > > Of course we may end up eating crow if all the other platforms have the > > same problem, since we clearly can''t remove support for all platforms... > > > >> The 1:1 mapping is a workaround and MUST be remove as soon as a SYS MMU is > >> implemented in XEN. > > > > I wonder if we can make this conditional on a suitable board level DT > > compat node ("samsung,arndale" or "samsung,exynos5250" perhaps)? And > > print a big warning when enabling it of course. > > > What do you think about adding a workaround field in platform structure? > It will contains PLATFORM_WORKAROUND_DOM0_11_MAPPING and perhaps other > workaround if we really need it... > > This could avoid to check DT compat node for each platform where Xen > need to do a 1:1 mapping for dom0.Sure, if that works then that is even better. People tend to call these things QUIRKS rather than WORKAROUNDS.> > >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > >> --- > >> xen/arch/arm/domain_build.c | 51 ++++++++++++++++++++++++------------------- > >> xen/arch/arm/kernel.h | 1 - > >> 2 files changed, 28 insertions(+), 24 deletions(-) > >> > >> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > >> index ced73a7..11298e1 100644 > >> --- a/xen/arch/arm/domain_build.c > >> +++ b/xen/arch/arm/domain_build.c > >> @@ -66,29 +66,36 @@ static int set_memory_reg(struct domain *d, struct kernel_info *kinfo, > >> int address_cells, int size_cells, u32 *new_cell) > >> { > >> int reg_size = (address_cells + size_cells) * sizeof(*cell); > >> - int l = 0; > >> - u64 start; > >> - u64 size; > >> + paddr_t start; > >> + paddr_t size; > >> + struct page_info *pg; > >> + unsigned int order = get_order_from_bytes(dom0_mem); > >> + int res; > >> + paddr_t spfn; > >> > >> - while ( kinfo->unassigned_mem > 0 && l + reg_size <= len > >> - && kinfo->mem.nr_banks < NR_MEM_BANKS ) > >> - { > >> - device_tree_get_reg(&cell, address_cells, size_cells, &start, &size); > >> - if ( size > kinfo->unassigned_mem ) > >> - size = kinfo->unassigned_mem; > >> - device_tree_set_reg(&new_cell, address_cells, size_cells, start, size); > >> - > >> - printk("Populate P2M %#"PRIx64"->%#"PRIx64"\n", start, start + size); > >> - p2m_populate_ram(d, start, start + size); > >> - kinfo->mem.bank[kinfo->mem.nr_banks].start = start; > >> - kinfo->mem.bank[kinfo->mem.nr_banks].size = size; > >> - kinfo->mem.nr_banks++; > >> - kinfo->unassigned_mem -= size; > >> - > >> - l += reg_size; > >> - } > >> + pg = alloc_domheap_pages(d, order, 0); > >> + if ( !pg ) > >> + panic("Failed to allocate contiguous memory for dom0\n"); > > > > Interesting, so we don''t actually need RAM to start at the same place as > > the real hardware would have it and the kernel copes? Slight surprising > > the kernel didn''t whine, but OK! > > I didn''t see specific warning from the kernel. Why the kernel should > whine if the memory banks have changed?I just imagined that the kernel would assume that PHYS_OFFSET for a given platform was static, e.g. memory on the platform starts at 0x80000000 but we are giving it an arbitrary 128M aligned region, e.g. stating at 0x88000000 or something, I''m just surprised something didn''t break! Ian.
Ian Campbell
2013-Apr-30 09:12 UTC
Re: [RFC 23/29] xen/arm: Add versatile express platform
On Mon, 2013-04-29 at 18:52 +0100, Julien Grall wrote:> On 04/29/2013 05:27 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > >> This platform contains nearly nothing specific except the reset function. > >> > >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > > > Acked-by: Ian Campbell <ian.campbell@citrix.com> > > > >> +/* Board-specific: base address of system controller */ > >> +#define SP810_ADDRESS 0x1C020000 > > > > Even better would be if this is in DT. > > It seems there is an *arm,vexpress-reset* node in the device tree. > > It needs some work, so I will send a separate patch to add support for > the vexpress-reset function.That''s fine. If you are respinning this patch you could add an "XXX get from DT" marker. Ian.
Ian Campbell
2013-Apr-30 09:18 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On Mon, 2013-04-29 at 19:12 +0100, Julien Grall wrote:> On 04/29/2013 05:45 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > >> Add CONFIG_EARLY_PRINTK options in configs/arm{32,64}.mk to let the user > >> to choose if he wants to have early output, ie before the console is initialized. > > > > These shouldn''t go in config/arm*.mk but should be handed in > > xen/arch/arm/ > > > I don''t understand why, it''s a config option and the user can modify > arm32.mkHeh, I forgot I''d said this already and repeated myself this morning, oops! The thing is that arm*.mk (and the other *.mk) tend towards things which are statically different between platforms, not actual user configurable stuff. The problem is that we don''t have much on the way of user configurable stuff in the hypervisor, so we don''t have much infrastructure and or precedent.> >> +# Xen early debugging function > >> +# This is helpful if you are debbuging code that executes before the console > >> +# is initialized. > >> +# Note that selecting this option will limit Xen to a single UART > >> +# definition. Attempting to boot Xen image on a different platform *will > >> +# not work*, so this option should not be enable for Xens that are > >> +# intended to be portable. > >> +# Possible value: > >> +# - none: no early printk > > > > Blank/unset would represent none? Or you mean literal "none"? > > I choose to use literal "none", but finally I think it''s better to have > blank/unset.It would be more customary to have the variable be not set, I think.> > >> +# - pl011: printk with PL011 UART > >> +CONFIG_EARLY_PRINTK := none > > > > I guess you mean literal none... > > > > Can this be overriden on command line or in .config? You may need to > > use ?= so it can be. > > Yes. Make overrides all "local" variables with the ones on the command line.What about .config ?> >> diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile > >> index 1ad3364..6af8ca3 100644 > >> --- a/xen/arch/arm/arm32/Makefile > >> +++ b/xen/arch/arm/arm32/Makefile > >> @@ -5,4 +5,7 @@ obj-y += mode_switch.o > >> obj-y += proc-ca15.o > >> > >> obj-y += traps.o > >> -obj-y += domain.o > >> \ No newline at end of file > >> +obj-y += domain.o > >> + > >> +obj-$(EARLY_PRINTK) += debug.o > >> +obj-$(CONFIG_EARLY_PL011) += debug-pl011.o > > > > This could become > > obj-$(EARLY_PRINTK) += debug-$(CONFIG_EARLY_PRINTK).o > > and save adding a new one for each name? And if you create a stub > > debug-none.S you could just make it obj-y ? Should we gate this on > > debug=y? > > > What does debug=y do?It turns on ASSERTS and undefs the NDEBUG define which is used to surround bits of debugging code and stuff like that etc. It also implies other things like verbose=y and debug symbols in the hypervisor binary (i.e. passes -g to gcc/ld).> I think we don''t need debug-none.S if CONFIG_EARLY_PRINTK is unset when > early printk is disabled. We just need to check in Rules.mk is > CONFIG_EARLY_PRINTK is set or not and defined EARLY_PRINTK.That sounds workable, will wait to see how it ends up looking Ian.
On Mon, 2013-04-29 at 19:20 +0100, Julien Grall wrote:> On 04/29/2013 05:13 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > >> Hello, > >> > >> This patch series is divided in 4 parts: > >> - Patch 1-6: Minor bug fixes > >> - Patch 7-10: Add hierarchical device tree support based on linux tree > >> - Patch 11-24: Remove harcoded part > >> - Patch 25-28: Arndale support based on Anthony''s git > >> > >> Xen can boot on both Arndale Board and the Versatile Express without > >> recompilation. But there is still some hardcoded part, mainly in assembly. > >> > >> Things to do: > >> - Move secondary CPUs bring up code in platform specific > >> - Move out of Xen the switch between secure mode and hypervisor mode > >> - Rework dom0 device tree creation > >> - Use everywhere the new device tree API > >> - Add a support for SYS MMU > >> > >> If you want to try this patch series you can clone: > >> git clone -b arm git://xenbits.xen.org/people/julieng/xen-unstable.git > > > > From the wiki it seems that this also requires a non-mainline kernel (a > > linaro derived thing?). How close is arndale support to being > > upstream/mainline? > > The wiki page point to a linux 3.7 whit linaro patches and xen patches. > > It''s seems the Arndale support is nearly completed on 3.9. It''s a matter > of about ten patches. > > I would prefer to stick on linaro tree to avoid to maintain our own > Linux Arndale tree. We can switch to a linux upstream once the Arndale > is fully supported.Yes, absolutely, the tree should either be Linaro or upstream mainline not one of our won. If the long term trajectory is that mainline will be usable in some future version that''s perfect. Ian.
On Mon, 2013-04-29 at 19:21 +0100, Julien Grall wrote:> On 04/29/2013 07:12 PM, Anthony PERARD wrote: > > > On 29/04/13 17:51, Ian Campbell wrote: > >> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > >>> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > > > Julien, could you add my signed off before yours? > > > Yes. I will add to the next patch series.If Anthony is the primary author of the patch then you should include a From: psuedo-header as the first line of the mail. If you "git commit --amend --author=''Anthony PERARD <anthon...@citrix.com>'' then git send email and friends will do the right thing. If there are other patches which need to be attributed to Anthony then please do so as well. Ian.
Ian Campbell
2013-Apr-30 09:22 UTC
Re: [RFC 08/29] xen/arm: Add helpers to use the device tree
On Mon, 2013-04-29 at 19:23 +0100, Julien Grall wrote:> On 04/29/2013 05:55 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 16:40 +0100, Julien Grall wrote: > >> On 04/29/2013 04:23 PM, Ian Campbell wrote: > >> > >>> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > >>> > >>> Are these also from Linux? > >>> > >>>> Signed-off-by: Julien Grall <julien.grall@linaro.org> > >>>> --- > >>>> xen/common/device_tree.c | 120 +++++++++++++++++++++++++++++++++++++++++ > >>>> xen/include/xen/device_tree.h | 120 +++++++++++++++++++++++++++++++++++++++++ > >>>> 2 files changed, 240 insertions(+) > >>>> > >>>> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > >>>> index 05285b7..dd4b813 100644 > >>>> --- a/xen/common/device_tree.c > >>>> +++ b/xen/common/device_tree.c > >>>> @@ -573,6 +573,54 @@ const void *dt_get_property(const struct dt_device_node *np, > >>>> return pp ? pp->value : NULL; > >>>> } > >>>> > >>>> +bool_t dt_device_is_compatible(const struct dt_device_node *device, > >>>> + const char *compat) > >>>> +{ > >>>> + const char* cp; > >>>> + u32 cplen, l; > >>>> + > >>>> + cp = dt_get_property(device, "compatible", &cplen); > >>>> + if ( cp == NULL ) > >>>> + return 0; > >>>> + while ( cplen > 0 ) > >>>> + { > >>>> + if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 ) > >>> > >>> We have functions which do this already, don''t we? Also things like > >>> dt_node_cmp, dt_read_number etc have analogues in the current code. > >>> > >>> If these are from Linux I''m inclined to believe they will be better than > >>> our own. For 4.4 we should look at removing our variants. > >>> > >>> Or maybe if I keep reading the series I will find them going away > >>> already? > >> > >> > >> In fact it''s exactly the same, except the current function deals with > >> flat device tree and the new one deals with the hierarchical device tree. > >> > >> I''m afraid we can''t remove this duplicate code, we still need it for > >> early scan of the device tree to retrieve memory, cpus, and modules > >> informations. > > > > We can''t use dt_compat_cmp in the early code? > > Oh right, I though you were talking about dt_device_is_compatible and > device_tree_node_compatible.Sorry I wasn''t very clear there... Ian.
Ian Campbell
2013-Apr-30 09:34 UTC
Re: [RFC 13/29] xen/arm: Use hierarchical device tree to retrieve GIC information
On Mon, 2013-04-29 at 21:42 +0100, Julien Grall wrote:> On 04/29/2013 04:35 PM, Ian Campbell wrote: > > > On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: > >> - Remove early parsing for GIC addresses > >> - Remove hard coded maintenance IRQ number > > > > At last, the payoff! > > > >> > >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > >> --- > >> xen/arch/arm/gic.c | 63 ++++++++++++++++++++++++++++------------- > >> xen/common/device_tree.c | 42 --------------------------- > > > > I like this line! > > > >> @@ -464,7 +486,7 @@ void gic_route_ppis(void) > >> { > >> /* XXX should get these from DT */ > >> /* GIC maintenance */ > >> - gic_route_irq(25, 1, 1u << smp_processor_id(), 0xa0); > >> + gic_route_dt_irq(&gic.maintenance, 1u << smp_processor_id(), 0xa0); > >> /* Hypervisor Timer */ > >> gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0); > >> /* Virtual Timer */ > >> @@ -813,7 +835,8 @@ void gic_dump_info(struct vcpu *v) > >> > >> void __cpuinit init_maintenance_interrupt(void) > >> { > >> - request_irq(25, maintenance_interrupt, 0, "irq-maintenance", NULL); > >> + request_irq(gic.maintenance.irq, maintenance_interrupt, > >> + 0, "irq-maintenance", NULL); > > > > Would a dt_request_irq be useful anywhere other than here? > > As all the interrupts should be retrieved from the device_tree could we > remove request_irq for ARM (ie move request_irq definition to > asm-x86/irq.h)? It''s also a safe guard for developper to avoid hardcoded > IRQ.Might be something to consider for 4.4, needs discussion with the x86 chaps and Keir? Since request_irq is implerment in arch code we could just skip it, then link errors would do the rest.> Then we can: > 1) modify irq argument type > 2) rename the function in request_dt_irq > > I''m not sure the latter is usefull. >
Ian Campbell
2013-Apr-30 09:53 UTC
Re: [RFC 26/29] xen/arm: Add Exynos 4210 UART support for early printk
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> Signed-off-by: Julien Grall <julien.grall@linaro.org>Can you arrange to share a header with the non-early version and avoid the opencoded register and bit definitions?> --- > config/arm32.mk | 1 + > xen/arch/arm/Rules.mk | 4 ++ > xen/arch/arm/arm32/Makefile | 1 + > xen/arch/arm/arm32/debug-exynos5.S | 81 ++++++++++++++++++++++++++++++++++++ > 4 files changed, 87 insertions(+) > create mode 100644 xen/arch/arm/arm32/debug-exynos5.S > > diff --git a/config/arm32.mk b/config/arm32.mk > index 593a1d1..01c1490 100644 > --- a/config/arm32.mk > +++ b/config/arm32.mk > @@ -17,6 +17,7 @@ CFLAGS += -marm > # Possible value: > # - none: no early printk > # - pl011: printk with PL011 UART > +# - exynos5: printk with the second exynos 5 UARTFrom the subject I infer that this UART is an Exynos 4210? If so I think that is the correct name to use here, consistent with the pl011 name above. (the alternative is that the pl011 is wrong...). I suppose in principal a single driver might apply to multiple platforms but with different base addresses, but that at build time you need to choose a specific platform, which implies a particular driver. The current infrastructure doesn''t really express that notion. What about if we support a mutually exclusive (enforced only by the clash of symbols at link time) set of: CONFIG_EARLY_UART_PL011 CONFIG_EARLY_UART_EXYNOS4210 which if defined must be set to the physical address of the port? This would mean users need to know the address of the UART on their platform rather than just being able to name the platform though. Perhaps that''s a feature not a bug (i.e. they can choose which UART of multiple UARTs if they want). I suppose we could also support CONFIG_EARY_UART_PLATFORM=foo and translate into the above. Or are there other hardcoded parameters (e.g. crystal rate) which stop this?> CONFIG_EARLY_PRINTK := none > HAS_PL011 := y > HAS_EXYNOS5 := y > diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk > index 2053b1e..7dcc0b7 100644 > --- a/xen/arch/arm/Rules.mk > +++ b/xen/arch/arm/Rules.mk > @@ -43,5 +43,9 @@ ifeq ($(CONFIG_EARLY_PRINTK), pl011) > EARLY_PRINTK := y > CONFIG_EARLY_PL011 := y > endif > +ifeq ($(CONFIG_EARLY_PRINTK), exynos5) > +EARLY_PRINTK := y > +CONFIG_EARLY_EXYNOS5 := y > +endif > > CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK > diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile > index 6af8ca3..90e4eab 100644 > --- a/xen/arch/arm/arm32/Makefile > +++ b/xen/arch/arm/arm32/Makefile > @@ -9,3 +9,4 @@ obj-y += domain.o > > obj-$(EARLY_PRINTK) += debug.o > obj-$(CONFIG_EARLY_PL011) += debug-pl011.o > +obj-$(CONFIG_EARLY_EXYNOS5) += debug-exynos5.o > diff --git a/xen/arch/arm/arm32/debug-exynos5.S b/xen/arch/arm/arm32/debug-exynos5.S > new file mode 100644 > index 0000000..cbe1705 > --- /dev/null > +++ b/xen/arch/arm/arm32/debug-exynos5.S > @@ -0,0 +1,81 @@ > +/* > + * xen/arch/arm/arm32/debug-exynos5.S > + * > + * Exynos 5 specific debug code > + * > + * Copyright (c) 2013 Citrix Systems. > + * > + * 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. > + */ > + > +#include <asm/asm_defns.h> > + > +#define EXYNOS5_UART_BASE_ADDRESS 0x12c20000 > + > +.globl early_uart_paddr > +early_uart_paddr: .word EXYNOS5_UART_BASE_ADDRESS > + > +/* Exynos 5 UART initialization > + * r11: UART base address > + * Clobber r0-r1 */ > +.globl early_uart_init > +early_uart_init: > + /* init clock */ > + ldr r1, =0x10020000 > + /* select MPLL (800MHz) source clock */ > + ldr r0, [r1, #0x250] > + and r0, r0, #(~(0xf<<8)) > + orr r0, r0, #(0x6<<8) > + str r0, [r1, #0x250] > + /* ration 800/(7+1) */What does "ration" mean here? It doesn''t seem to correspond to the French for denominator, numerator, remainder or ratio (at least not according to Google Translate ;-))> + ldr r0, [r1, #0x558] > + and r0, r0, #(~(0xf<<8)) > + orr r0, r0, #(0x7<<8) > + str r0, [r1, #0x558] > + > + mov r1, #4 > + str r1, [r11, #0x2c] /* -> UARTIBRD (Baud divisor fraction) */ > + mov r1, #53 > + str r1, [r11, #0x28] /* -> UARTIBRD (Baud divisor integer) */ > + mov r1, #3 /* 8n1 */ > + str r1, [r11, #0x0] /* -> (Line control) */ > + ldr r1, =(1<<2) /* TX IRQMODE */ > + str r1, [r11, #0x4] /* -> (Control Register) */ > + mov r1, #0x0 > + str r1, [r11, #0x8] /* disable FIFO */ > + mov r1, #0x0 > + str r1, [r11, #0x0C] /* no auto flow control */ > + mov pc, lr > + > +/* Exynos 5 UART wait UART to be ready to transmit > + * r11: UART base address > + * Clobber r2 r11 */ > +.globl early_uart_ready > +early_uart_ready: > + ldr r2, [r11, #0x10] /* <- UTRSTAT (Flag register) */ > + tst r2, #(1<<1) /* Check BUSY bit */ > + beq early_uart_ready /* Wait for the UART to be ready */ > + mov pc, lr > + > +/* Exynos 5 UART transmit character > + * r2: character to transmit > + * r11: UART base address */ > +.globl early_uart_transmit > +early_uart_transmit: > + str r2, [r11, #0x20] /* -> UTXH (Data Register) */ > + mov pc, lr > + > +/* > + * Local variables: > + * mode: ASM > + * indent-tabs-mode: nil > + * End: > + */
Ian Campbell
2013-Apr-30 10:00 UTC
Re: [RFC 27/29] xen/arm: Add platform specific code for the exynos5
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/platforms/Makefile | 1 + > xen/arch/arm/platforms/exynos5.c | 105 +++++++++++++++++++++++++++++++ > xen/include/asm-arm/platforms/exynos5.h | 40 ++++++++++++ > 3 files changed, 146 insertions(+) > create mode 100644 xen/arch/arm/platforms/exynos5.c > create mode 100644 xen/include/asm-arm/platforms/exynos5.h > > diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile > index 4313e95..ff2b65b 100644 > --- a/xen/arch/arm/platforms/Makefile > +++ b/xen/arch/arm/platforms/Makefile > @@ -1 +1,2 @@ > obj-y += vexpress.o > +obj-y += exynos5.o > diff --git a/xen/arch/arm/platforms/exynos5.c b/xen/arch/arm/platforms/exynos5.c > new file mode 100644 > index 0000000..01e12b7 > --- /dev/null > +++ b/xen/arch/arm/platforms/exynos5.c > @@ -0,0 +1,105 @@ > +/* > + * xen/arch/arm/platforms/exynos5.c > + * > + * Exynos5 specific settings > + * > + * Julien Grall <julien.grall@linaro.org> > + * Copyright (c) 2013 Linaro Limited. > + * > + * 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. > + */ > + > +#include <asm/p2m.h> > +#include <xen/config.h> > +#include <xen/device_tree.h> > +#include <xen/domain_page.h> > +#include <xen/mm.h> > +#include <asm/platforms/exynos5.h> > +#include <asm/platform.h> > + > +static int exynos5_init_time(void) > +{ > + uint32_t reg; > + > + // enable timer on exynos5 arndale board > + // should probably be done by u-boot/* */ please.> + reg = platform_read_register(EXYNOS5_MCT_G_TCON); > + platform_write_register(EXYNOS5_MCT_G_TCON, reg | EXYNOS5_MCT_G_TCON_START); > + > + return 0; > +} > + > +/* Additionnal mapping for dom0 (Not in the DTS) */"Additional mappings"> +static int exynos5_specific_mapping(struct domain *d) > +{ > + paddr_t ma = 0; > + uint32_t *dst; > + int res; > + > + /* > + * Set temporary guest traps with 0xe14fff7c which is hvc(0xfffc) > + * a hyp panic! > + * TODO: Find why: > + * 1) Xen abort directly after local_abort_enable when > + * the p2m_populate_ram is not here.It will actually be aborting here somewhere but that abort can''t be delivered until the point aborts are enabled. My patch "xen: arm: enable aborts on all physical processors." will enable aborts much earlier so you might get a better indication of exactly where it goes wrong.> + * 2) Linux doesn''t start without this trickOuch. I presume it doesn''t actually end up calling hvc 0xfffc? Does it work if you just map/unmap without writing anything? What does Linux do without the trick? Touches address 0x0 perhaps? Would anything be mapped there on a real Exynos? I had a weird one running on the v8 foundation model where I had to add a NOP hypercall to Linux''s head.S before a certain point -- I wonder if this is related? It''ll be a missing flush or barrier of course, the question is where ;-)> + */ > + p2m_populate_ram(d, 0x0, 0x1000 - 1); > + > + res = gvirt_to_maddr(0, &ma); > + if ( res ) > + { > + printk(XENLOG_ERR "Unable to translate guest address\n"); > + return -EFAULT; > + } > + > + dst = map_domain_page(ma >> PAGE_SHIFT); > + dst[2] = 0xe14fff7c; > + unmap_domain_page(dst); > + > + /* Map the chip ID */ > + map_mmio_regions(d, EXYNOS5_PA_CHIPID, EXYNOS5_PA_CHIPID + PAGE_SIZE - 1, > + EXYNOS5_PA_CHIPID); > + > + /* Map the PWM region */ > + map_mmio_regions(d, EXYNOS5_PA_TIMER, > + EXYNOS5_PA_TIMER + (PAGE_SIZE * 2) - 1, > + EXYNOS5_PA_TIMER); > + > + return 0; > +} > + > +static void exynos5_reset(void) > +{ > + platform_write_register(EXYNOS5_SWRESET, 1); > +} > + > +static const char const *exynos5_dt_compat[] __initdata > +{ > + "samsung,exynos5250", > + NULL > +}; > + > +PLATFORM_START(exynos5, "SAMSUNG EXYNOS5") > + .compatible = exynos5_dt_compat, > + .init_time = exynos5_init_time, > + .specific_mapping = exynos5_specific_mapping, > + .reset = exynos5_reset, > +PLATFORM_END > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/include/asm-arm/platforms/exynos5.h b/xen/include/asm-arm/platforms/exynos5.h > new file mode 100644 > index 0000000..d77623c > --- /dev/null > +++ b/xen/include/asm-arm/platforms/exynos5.h > @@ -0,0 +1,40 @@ > +#ifndef __ASM_ARM_PLATFORMS_EXYNOS5_H > +#define __ASM_ASM_PLATFORMS_EXYSNO5_H > + > +#define EXYNOS5_MCT_BASE 0x101c0000 > +#define EXYNOS5_MCTREG(x) (EXYNOS5_MCT_BASE + (x)) > +#define EXYNOS5_MCT_G_TCON EXYNOS5_MCTREG(0x240) > +#define EXYNOS5_MCT_G_TCON_START (1 << 8) > + > +#define EXYNOS5_PA_CHIPID 0x10000000 > +#define EXYNOS5_PA_TIMER 0x12dd0000 > +/* Base address of system controller */ > +#define EXYNOS5_PA_PMU 0x10040000 > + > +#define EXYNOS5_SWRESET (EXYNOS5_PA_PMU + 0x0400) > + > +#define S5P_PA_SYSRAM 0x02020000 > + > +/* Constants below is only used in assembly because the DTS is not yet parsed */ > +#ifdef __ASSEMBLY__ > + > +/* GIC Base Address */ > +#define EXYNOS5_GIC_BASE_ADDRESS 0x10480000 > + > +/* Timer''s frequency */ > +#define EXYNOS5_TIMER_FREQUENCY (24 * 1000 * 1000) /* 24 MHz */ > + > +/* Arndale machine ID */ > +#define MACH_TYPE_SMDK5250 3774 > + > +#endif /* __ASSEMBLY__ */ > + > +#endif /* __ASM_ARM_PLATFORMS_EXYNOS5_H */ > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */
Ian Campbell
2013-Apr-30 10:10 UTC
Re: [RFC 28/29] xen/arm: Support secondary cpus boot and switch to hypervisor for the exynos5
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> Use machine ID to know what is the current board. This value is only given > to the first CPU by the bootloader. > > When the exynos 5 starts, there is only one CPU up. Xen needs to start the > secondary cpu. The latter boots in secure mode.Please can you put a big note here about the temporary nature of these hacks and the eventual move to a boot-wrapper like setup?> > Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/arm32/head.S | 19 +++++++- > xen/arch/arm/arm32/mode_switch.S | 74 ++++++++++++++++++++++-------- > xen/include/asm-arm/platforms/vexpress.h | 11 +++++ > 3 files changed, 85 insertions(+), 19 deletions(-) > > diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S > index 55781cd..f701bc0 100644 > --- a/xen/arch/arm/arm32/head.S > +++ b/xen/arch/arm/arm32/head.S > @@ -72,7 +72,7 @@ past_zImage: > cpsid aif /* Disable all interrupts */ > > /* Save the bootloader arguments in less-clobberable registers */ > - /* No need to save r1 == Unused ARM-linux machine type */ > + mov r5, r1 /* r5: ARM-linux machine type */:> mov r8, r2 /* r8 := DTB base address */ > > /* Find out where we are */ > @@ -122,6 +122,20 @@ boot_cpu: > teq r12, #0 > bleq kick_cpus > > + /* Secondary CPUs doesn''t have machine ID > + * - Store machine on boot CPU > + * - Load machine ID on secondary CPUs */ > + ldr r0, =machine_id /* VA of machine_id */ > + add r0, r0, r10 /* PA of machine_id */ > + teq r12, #0 > + streq r5, [r0] /* On boot CPU save machine ID */You never read this. Keeping it solely in r5 in head.S will help avoid these hacks leaking further into Xen.> + ldrne r5, [r0] /* If non boot cpu r5 := machine ID */ > + > + PRINT("- Machine ID ") > + mov r0, r5 > + bl putn > + PRINT(" -\r\n")This is after the call to kick_cpus, which appears to want to use the result? Since this is a hack to workaround insufficient firmware I''d prefer to keep the body of this outside of head.S, can we follow a pattern like how we deal with cortex_a15_init?> + > /* Check that this CPU has Hyp mode */ > mrc CP32(r0, ID_PFR1) > and r0, r0, #0xf000 /* Bits 12-15 define virt extensions */ > @@ -402,6 +416,9 @@ putn: mov pc, lr > > #endif /* !EARLY_PRINTK */ > > +/* Place holder for machine ID */ > +machine_id: .word 0x0 > + > /* > * Local variables: > * mode: ASM > diff --git a/xen/arch/arm/arm32/mode_switch.S b/xen/arch/arm/arm32/mode_switch.S > index d6741d0..ab40f18 100644 > --- a/xen/arch/arm/arm32/mode_switch.S > +++ b/xen/arch/arm/arm32/mode_switch.S > @@ -20,14 +20,20 @@ > #include <asm/config.h> > #include <asm/page.h> > #include <asm/platforms/vexpress.h> > +#include <asm/platforms/exynos5.h> > #include <asm/asm_defns.h> > #include <asm/gic.h> > > - > -/* XXX: Versatile Express specific code */ > -/* wake up secondary cpus */ > +/* Wake up secondary cpus > + * This code relies on Machine ID and only works for Vexpress and the Arndale > + * TODO: Move this code either later (via platform specific desc) or in a bootwrapper > + * r5: Machine ID > + * Clobber r0 r2 */ > .globl kick_cpus > kick_cpus: > + ldr r0, =MACH_TYPE_SMDK5250 > + teq r5, r0 /* Are we running on the arndale? */ > + beq kick_cpus_arndaleCan you add: /* Otherwise vexpress */ where we fall through here. Or even better if we are going to have this hack lets just check for the vexpress machid too.> /* write start paddr to v2m sysreg FLAGSSET register */ > ldr r0, =(V2M_SYS_MMIO_BASE) /* base V2M sysreg MMIO address */ > dsb > @@ -38,8 +44,20 @@ kick_cpus: > add r2, r2, r10 > str r2, [r0, #(V2M_SYS_FLAGSSET)] > dsb > + ldr r2, =V2M_GIC_BASE_ADDRESS /* r2 := VE gic base address */ > + b kick_cpus_sgi > +kick_cpus_arndale: > + /* write start paddr to CPU 1 sysreg register */ > + ldr r0, =(S5P_PA_SYSRAM) > + ldr r2, =start > + add r2, r2, r10 > + str r2, [r0] > + dsb > + ldr r2, =EXYNOS5_GIC_BASE_ADDRESS /* r2 := Exynos5 gic base address */ > +kick_cpus_sgi: > /* send an interrupt */ > - ldr r0, =(GIC_BASE_ADDRESS + GIC_DR_OFFSET) /* base GICD MMIO address */ > + ldr r0, =GIC_DR_OFFSET /* GIC distributor offset */ > + add r0, r2 /* r0 := r0 + gic base address */ > mov r2, #0x1 > str r2, [r0, #(GICD_CTLR * 4)] /* enable distributor */ > mov r2, #0xfe0000 > @@ -51,13 +69,15 @@ kick_cpus: > > /* Get up a CPU into Hyp mode. Clobbers r0-r3. > * > - * Expects r12 == CPU number > + * r5: Machine ID > + * r12: CPU number > * > - * This code is specific to the VE model, and not intended to be used > + * This code is specific to the VE model/Arndale, and not intended to be used > * on production systems. As such it''s a bit hackier than the main > * boot code in head.S. In future it will be replaced by better > * integration with the bootloader/firmware so that Xen always starts > - * in Hyp mode. */ > + * in Hyp mode. > + * Clobber r0 - r4 */ > > .globl enter_hyp_mode > enter_hyp_mode: > @@ -68,33 +88,51 @@ enter_hyp_mode: > orr r0, r0, #0xb1 /* Set SCD, AW, FW and NS */ > bic r0, r0, #0xe /* Clear EA, FIQ and IRQ */ > mcr CP32(r0, SCR) > + > + ldr r2, =MACH_TYPE_SMDK5250 /* r4 := Arndale machine ID */ > + /* By default load Arndale defaults values */ > + ldr r0, =EXYNOS5_TIMER_FREQUENCY /* r0 := timer''s frequency */ > + ldr r1, =EXYNOS5_GIC_BASE_ADDRESS /* r1 := GIC base address */ > + /* If it''s not the Arndale machine ID, load VE values */ > + teq r5, r2 > + ldrne r0, =V2M_TIMER_FREQUENCY > + ldrne r1, =V2M_GIC_BASE_ADDRESSAre these processor or platform specific? If processor can they be handled like how proc-ca15.S:cortex_a15_init does things?> + > /* Ugly: the system timer''s frequency register is only > * programmable in Secure state. Since we don''t know where its > * memory-mapped control registers live, we can''t find out the > - * right frequency. Use the VE model''s default frequency here. */ > - ldr r0, =0x5f5e100 /* 100 MHz */ > + * right frequency. */ > mcr CP32(r0, CNTFRQ) > ldr r0, =0x40c00 /* SMP, c11, c10 in non-secure mode */ > mcr CP32(r0, NSACR) > - mov r0, #GIC_BASE_ADDRESS > - add r0, r0, #GIC_DR_OFFSET > + > + add r0, r1, #GIC_DR_OFFSET > /* Disable the GIC distributor, on the boot CPU only */ > - mov r1, #0 > + mov r4, #0 > teq r12, #0 /* Is this the boot CPU? */ > - streq r1, [r0] > + streq r4, [r0] > /* Continuing ugliness: Set up the GIC so NS state owns interrupts, > * The first 32 interrupts (SGIs & PPIs) must be configured on all > * CPUs while the remainder are SPIs and only need to be done one, on > * the boot CPU. */ > add r0, r0, #0x80 /* GICD_IGROUP0 */ > mov r2, #0xffffffff /* All interrupts to group 1 */ > - teq r12, #0 /* Boot CPU? */ > str r2, [r0] /* Interrupts 0-31 (SGI & PPI) */ > - streq r2, [r0, #4] /* Interrupts 32-63 (SPI) */ > - streq r2, [r0, #8] /* Interrupts 64-95 (SPI) */ > + teq r12, #0 /* Boot CPU? */ > + bne skip_spis /* Don''t route SPIs on secondary CPUs */ > + > + add r4, r1, #GIC_DR_OFFSET > + ldr r4, [r4, #4] /* r4 := Interrupt Controller Type Reg */ > + and r4, r4, #GICD_TYPE_LINES /* r4 := number of SPIs */ > + /* Assume we have minimum 32 SPIs */It''d be relatively easy to turn this do {} while construct into a while() {} one and avoid this assumption?> +1: > + add r0, r0, #4 /* Go to the new group */ > + str r2, [r0] /* Update the group */ > + subs r4, r4, #1 > + bne 1b > +skip_spis: > /* Disable the GIC CPU interface on all processors */ > - mov r0, #GIC_BASE_ADDRESS > - add r0, r0, #GIC_CR_OFFSET > + add r0, r1, #GIC_CR_OFFSET > mov r1, #0 > str r1, [r0] > /* Must drop priority mask below 0x80 before entering NS state */ > diff --git a/xen/include/asm-arm/platforms/vexpress.h b/xen/include/asm-arm/platforms/vexpress.h > index 5cf3aba..982a293 100644 > --- a/xen/include/asm-arm/platforms/vexpress.h > +++ b/xen/include/asm-arm/platforms/vexpress.h > @@ -32,6 +32,17 @@ > int vexpress_syscfg(int write, int function, int device, uint32_t *data); > #endif > > +/* Constants below is only used in assembly because the DTS is not yet parsed */ > +#ifdef __ASSEMBLY__ > + > +/* GIC base address */ > +#define V2M_GIC_BASE_ADDRESS 0x2c000000 > + > +/* Timer''s frequency */ > +#define V2M_TIMER_FREQUENCY 0x5f5e100 /* 100 Mhz */ > + > +#endif /* __ASSEMBLY__ */ > + > #endif /* __ASM_ARM_PLATFORMS_VEXPRESS_H */ > /* > * Local variables:
Ian Campbell
2013-Apr-30 10:11 UTC
Re: [RFC 29/29] xen/arm64: Remove hardcoded value for gic in assembly code
On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote:> - arm64: use V2M_GIC_BASE_ADDRESS > - only expose GIC_*_ADDRESS to assembly. The C code uses base addresses > provide by the device tree > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>> diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h > index 943175f..eb13bf4 100644 > --- a/xen/include/asm-arm/config.h > +++ b/xen/include/asm-arm/config.h > @@ -141,12 +141,16 @@ extern unsigned long frametable_virt_end; > #define watchdog_disable() ((void)0) > #define watchdog_enable() ((void)0) > > -/* Board-specific: base address of GIC + its regs */ > -#define GIC_BASE_ADDRESS 0x2c000000 > +#ifdef __ASSEMBLY__This is a good idea!> +/* Board-specific: regs base address for the GIC > + * Theses constants are only intend to be used in assembly file > + * because the DT is not yet parsed.t diffStray gi"t diff" here ;-)> + */ > #define GIC_DR_OFFSET 0x1000 > #define GIC_CR_OFFSET 0x2000 > #define GIC_HR_OFFSET 0x4000 /* Guess work http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/064219.html */ > #define GIC_VR_OFFSET 0x6000 /* Virtual Machine CPU interface) */ > +#endif /* __ASSEMBLY__ */ > > #endif /* __ARM_CONFIG_H__ */ > /*
Julien Grall
2013-Apr-30 11:05 UTC
Re: [RFC 18/29] xen/arm: add generic UART to get the device in the device tree
On 30 April 2013 10:09, Ian Campbell <Ian.Campbell@citrix.com> wrote:> On Mon, 2013-04-29 at 18:24 +0100, Julien Grall wrote: > > On 04/29/2013 04:51 PM, Ian Campbell wrote: > > > > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > > >> This generic UART will find the right UART via xen command line > > >> with com1=myserial. > > >> > > >> "myserial" is the alias of the UART in the device tree. Xen will > retrieve > > >> the information via the device tree and call the initialization > function for > > >> this specific UART thanks to the device API. > > >> > > >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > >> --- > > >> xen/arch/arm/setup.c | 3 +- > > >> xen/drivers/char/Makefile | 1 + > > >> xen/drivers/char/arm-uart.c | 76 > +++++++++++++++++++++++++++++++++++++++++++ > > >> xen/include/xen/serial.h | 8 +++++ > > >> 4 files changed, 87 insertions(+), 1 deletion(-) > > >> create mode 100644 xen/drivers/char/arm-uart.c > > >> > > >> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > > >> index 51f4bba..e5d8724 100644 > > >> --- a/xen/arch/arm/setup.c > > >> +++ b/xen/arch/arm/setup.c > > >> @@ -434,8 +434,9 @@ void __init start_xen(unsigned long > boot_phys_offset, > > >> #ifdef EARLY_UART_ADDRESS > > >> /* TODO Need to get device tree or command line for UART address > */ > > >> pl011_init(0, FIXMAP_ADDR(FIXMAP_CONSOLE)); > > >> - console_init_preirq(); > > >> #endif > > >> + arm_uart_init(); > > >> + console_init_preirq(); > > >> > > >> /* FIXME: Do something smarter */ > > >> dt_switch_to_printk(); > > >> diff --git a/xen/drivers/char/Makefile b/xen/drivers/char/Makefile > > >> index ab2246d..e68a54a 100644 > > >> --- a/xen/drivers/char/Makefile > > >> +++ b/xen/drivers/char/Makefile > > >> @@ -2,4 +2,5 @@ obj-y += console.o > > >> obj-$(HAS_NS16550) += ns16550.o > > >> obj-$(HAS_PL011) += pl011.o > > >> obj-$(HAS_EHCI) += ehci-dbgp.o > > >> +obj-$(CONFIG_ARM) += arm-uart.o > > >> obj-y += serial.o > > >> diff --git a/xen/drivers/char/arm-uart.c b/xen/drivers/char/arm-uart.c > > >> new file mode 100644 > > >> index 0000000..e242ae2 > > >> --- /dev/null > > >> +++ b/xen/drivers/char/arm-uart.c > > >> @@ -0,0 +1,76 @@ > > >> +/* > > >> + * xen/drivers/char/arm-uart.c > > >> + * > > >> + * Generic ARM uart retrieved via the device tree > > >> + * > > >> + * Julien Grall <julien.grall@linaro.org> > > >> + * Copyright (c) 2013 Linaro Limited. > > >> + * > > >> + * 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. > > >> + */ > > >> + > > >> +#include <asm/device.h> > > >> +#include <asm/early_printk.h> > > >> +#include <asm/types.h> > > >> +#include <xen/console.h> > > >> +#include <xen/device_tree.h> > > >> +#include <xen/mm.h> > > >> +#include <xen/serial.h> > > >> + > > >> +/* > > >> + * Configure serial port with string: devname > > >> + * Where devname is the alias of the device in the device tree > > >> + */ > > >> +static char __initdata opt_com1[30] = ""; > > >> +string_param("com1", opt_com1); > > > > > > com1 is a bit of an x86-ism. Can we use e.g. uart0 or does common code > > > constrain us here? > > > > > > > > > > Better would be to arrange things such that console=myserial does the > > > lookup. Then myserial=<foo> sets options for that device. > > > > > > I think you would need to add a call to dt_console_init to > > > console_init_preirq(), in the "Where should console output go?" loop. > > > > > > I don''t see an easy solution with dt_console_init. > > serial_parse_handle hardcodes the name of the serial, which only > > supports com1, com2, dbgp. Sadly, the serial initialization is made in > > the same function. > > Couldn''t it also hardcode a call to a "is this a dt serial alias" > function?Indeed. Can we assume Xen on Arm will use only one UART? We can modify the behaviour later.> > If I understand your suggestion, you suggest to use console=myserial > > where *myserial* is the alias on the DTB, right? > > Right. > > > In this case the name could clash with the hardcoded ones in Xen that is > not good. > > console=dt:<alias> ? Or to be honest I''m not sure that having the dt > aliases shadow the Xen hardcoded ones would be a bad thing -- the x86 > centric com<X> definition hardcoded in Xen is hardly likely to be useful > on ARM or any DT using platform. >I prefer dt:<alias> but how do we parse the configuration for the UART? Do we use dt:<alias>=configuration on the command line? In this case I don''t see function to retrieve a non-defined parameters on the command line. We should also take care about video card. In the future, the devices will be retrieved from the DTS. -- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Julien Grall
2013-Apr-30 11:21 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
Missing Xen devel mailing list. On 30 April 2013 12:19, Julien Grall <julien.grall@linaro.org> wrote:> > > > On 30 April 2013 10:18, Ian Campbell <Ian.Campbell@citrix.com> wrote: > >> On Mon, 2013-04-29 at 19:12 +0100, Julien Grall wrote: >> > On 04/29/2013 05:45 PM, Ian Campbell wrote: >> > >> > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> > >> Add CONFIG_EARLY_PRINTK options in configs/arm{32,64}.mk to let the >> user >> > >> to choose if he wants to have early output, ie before the console is >> initialized. >> > > >> > > These shouldn''t go in config/arm*.mk but should be handed in >> > > xen/arch/arm/ >> > >> > >> > I don''t understand why, it''s a config option and the user can modify >> > arm32.mk >> >> Heh, I forgot I''d said this already and repeated myself this morning, >> oops! >> >> The thing is that arm*.mk (and the other *.mk) tend towards things which >> are statically different between platforms, not actual user configurable >> stuff. >> >> The problem is that we don''t have much on the way of user configurable >> stuff in the hypervisor, so we don''t have much infrastructure and or >> precedent. >> >> > >> +# Xen early debugging function >> > >> +# This is helpful if you are debbuging code that executes before >> the console >> > >> +# is initialized. >> > >> +# Note that selecting this option will limit Xen to a single UART >> > >> +# definition. Attempting to boot Xen image on a different platform >> *will >> > >> +# not work*, so this option should not be enable for Xens that are >> > >> +# intended to be portable. >> > >> +# Possible value: >> > >> +# - none: no early printk >> > > >> > > Blank/unset would represent none? Or you mean literal "none"? >> > >> > I choose to use literal "none", but finally I think it''s better to have >> > blank/unset. >> >> It would be more customary to have the variable be not set, I think. >> >> > >> > >> +# - pl011: printk with PL011 UART >> > >> +CONFIG_EARLY_PRINTK := none >> > > >> > > I guess you mean literal none... >> > > >> > > Can this be overriden on command line or in .config? You may need to >> > > use ?= so it can be. >> > >> > Yes. Make overrides all "local" variables with the ones on the command >> line. >> >> What about .config ? >> > > I didn''t know that Xen can have a .config file. So I will use ?=. > > >> >> > >> diff --git a/xen/arch/arm/arm32/Makefile >> b/xen/arch/arm/arm32/Makefile >> > >> index 1ad3364..6af8ca3 100644 >> > >> --- a/xen/arch/arm/arm32/Makefile >> > >> +++ b/xen/arch/arm/arm32/Makefile >> > >> @@ -5,4 +5,7 @@ obj-y += mode_switch.o >> > >> obj-y += proc-ca15.o >> > >> >> > >> obj-y += traps.o >> > >> -obj-y += domain.o >> > >> \ No newline at end of file >> > >> +obj-y += domain.o >> > >> + >> > >> +obj-$(EARLY_PRINTK) += debug.o >> > >> +obj-$(CONFIG_EARLY_PL011) += debug-pl011.o >> > > >> > > This could become >> > > obj-$(EARLY_PRINTK) += debug-$(CONFIG_EARLY_PRINTK).o >> > > and save adding a new one for each name? And if you create a stub >> > > debug-none.S you could just make it obj-y ? Should we gate this on >> > > debug=y? >> > >> > >> > What does debug=y do? >> >> It turns on ASSERTS and undefs the NDEBUG define which is used to >> surround bits of debugging code and stuff like that etc. It also implies >> other things like verbose=y and debug symbols in the hypervisor binary >> (i.e. passes -g to gcc/ld). >> > > Thanks. Even if we gate CONFIG_EARLY_PRINTK to debug=y, we should let > the developper the option to disable/enable early printk. Otherwise we will > lost debug when Xen can boot on multiple board. > > -- > Julien Grall >-- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Julien Grall
2013-Apr-30 11:24 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On 30 April 2013 10:00, Ian Campbell <Ian.Campbell@citrix.com> wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > > diff --git a/config/arm32.mk b/config/arm32.mk > > index f64f0c1..83a7767 100644 > > --- a/config/arm32.mk > > +++ b/config/arm32.mk > > @@ -7,6 +7,17 @@ CONFIG_ARM_$(XEN_OS) := y > > # Explicitly specifiy 32-bit ARM ISA since toolchain default can be > -mthumb: > > CFLAGS += -marm > > > > +# Xen early debugging function > > +# This is helpful if you are debbuging code that executes before the > console > > +# is initialized. > > +# Note that selecting this option will limit Xen to a single UART > > +# definition. Attempting to boot Xen image on a different platform *will > > +# not work*, so this option should not be enable for Xens that are > > +# intended to be portable. > > +# Possible value: > > +# - none: no early printk > > +# - pl011: printk with PL011 UART > > +CONFIG_EARLY_PRINTK := none > > I''m wondering if this is the right place for this "config", other than > the load address (which is also arguably not supposed to be here), they > are mostly per-platform variables rather than user focussed config > options. > This new option seems more akin to the debug=y or CONFIG_DTB_FILE > buildtime options, which are mostly contained xen/Makefile and > xen/arch/arm/Makefile etc. > > I''m not really sure about this though -- the hypervisor doesn''t really > have much in the way of user tunable CONFIG options -- anyone else have > any opinions? > > >I think we need to have a "high" level way to choose the early printk driver. The user should not take care about the base address. Is .config is suitable for this kind of options? -- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Julien Grall
2013-Apr-30 11:52 UTC
Re: [RFC 28/29] xen/arm: Support secondary cpus boot and switch to hypervisor for the exynos5
On 30 April 2013 11:10, Ian Campbell <Ian.Campbell@citrix.com> wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > > Use machine ID to know what is the current board. This value is only > given > > to the first CPU by the bootloader. > > > > When the exynos 5 starts, there is only one CPU up. Xen needs to start > the > > secondary cpu. The latter boots in secure mode. > > Please can you put a big note here about the temporary nature of these > hacks and the eventual move to a boot-wrapper like setup?Ok.> > > > Signed-off-by: Julien Grall <julien.grall@linaro.org> > > --- > > xen/arch/arm/arm32/head.S | 19 +++++++- > > xen/arch/arm/arm32/mode_switch.S | 74 > ++++++++++++++++++++++-------- > > xen/include/asm-arm/platforms/vexpress.h | 11 +++++ > > 3 files changed, 85 insertions(+), 19 deletions(-) > > > > diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S > > index 55781cd..f701bc0 100644 > > --- a/xen/arch/arm/arm32/head.S > > +++ b/xen/arch/arm/arm32/head.S > > @@ -72,7 +72,7 @@ past_zImage: > > cpsid aif /* Disable all interrupts */ > > > > /* Save the bootloader arguments in less-clobberable registers > */ > > - /* No need to save r1 == Unused ARM-linux machine type */ > > + mov r5, r1 /* r5: ARM-linux machine type */ > > :> > > mov r8, r2 /* r8 := DTB base address */ > > > > /* Find out where we are */ > > @@ -122,6 +122,20 @@ boot_cpu: > > teq r12, #0 > > bleq kick_cpus > > > > + /* Secondary CPUs doesn''t have machine ID > > + * - Store machine on boot CPU > > + * - Load machine ID on secondary CPUs */ > > + ldr r0, =machine_id /* VA of machine_id */ > > + add r0, r0, r10 /* PA of machine_id */ > > + teq r12, #0 > > + streq r5, [r0] /* On boot CPU save machine ID > */ > > You never read this. Keeping it solely in r5 in head.S will help avoid > these hacks leaking further into Xen.I read just the line below, "ldrne r5, [r0]. I need this ugly trick because secondary CPUs directly start in Xen, so the register is not correctly set.> > + ldrne r5, [r0] /* If non boot cpu r5 :> machine ID */ > > + > > + PRINT("- Machine ID ") > > + mov r0, r5 > > + bl putn > > + PRINT(" -\r\n") > > This is after the call to kick_cpus, which appears to want to use the > result? >Right I could move this code before. I also use r5 in enter_hyp_mode.> Since this is a hack to workaround insufficient firmware I''d prefer to > keep the body of this outside of head.S, can we follow a pattern like > how we deal with cortex_a15_init?> + > > /* Check that this CPU has Hyp mode */ > > mrc CP32(r0, ID_PFR1) > > and r0, r0, #0xf000 /* Bits 12-15 define virt > extensions */ > > @@ -402,6 +416,9 @@ putn: mov pc, lr > > > > #endif /* !EARLY_PRINTK */ > > > > +/* Place holder for machine ID */ > > +machine_id: .word 0x0 > > + > > /* > > * Local variables: > > * mode: ASM > > diff --git a/xen/arch/arm/arm32/mode_switch.S > b/xen/arch/arm/arm32/mode_switch.S > > index d6741d0..ab40f18 100644 > > --- a/xen/arch/arm/arm32/mode_switch.S > > +++ b/xen/arch/arm/arm32/mode_switch.S > > @@ -20,14 +20,20 @@ > > #include <asm/config.h> > > #include <asm/page.h> > > #include <asm/platforms/vexpress.h> > > +#include <asm/platforms/exynos5.h> > > #include <asm/asm_defns.h> > > #include <asm/gic.h> > > > > - > > -/* XXX: Versatile Express specific code */ > > -/* wake up secondary cpus */ > > +/* Wake up secondary cpus > > + * This code relies on Machine ID and only works for Vexpress and the > Arndale > > + * TODO: Move this code either later (via platform specific desc) or in > a bootwrapper > > + * r5: Machine ID > > + * Clobber r0 r2 */ > > .globl kick_cpus > > kick_cpus: > > + ldr r0, =MACH_TYPE_SMDK5250 > > + teq r5, r0 /* Are we running on the > arndale? */ > > + beq kick_cpus_arndale > > Can you add: > /* Otherwise vexpress */ > where we fall through here. Or even better if we are going to have this > hack lets just check for the vexpress machid too.Unfortunately the fast models doesn''t set the machine ID (it''s always 0). That''s why I choose to let vexpress values as a fallback.> > /* write start paddr to v2m sysreg FLAGSSET register */ > > ldr r0, =(V2M_SYS_MMIO_BASE) /* base V2M sysreg MMIO > address */ > > dsb > > @@ -38,8 +44,20 @@ kick_cpus: > > add r2, r2, r10 > > str r2, [r0, #(V2M_SYS_FLAGSSET)] > > dsb > > + ldr r2, =V2M_GIC_BASE_ADDRESS /* r2 := VE gic base > address */ > > + b kick_cpus_sgi > > +kick_cpus_arndale: > > + /* write start paddr to CPU 1 sysreg register */ > > + ldr r0, =(S5P_PA_SYSRAM) > > + ldr r2, =start > > + add r2, r2, r10 > > + str r2, [r0] > > + dsb > > + ldr r2, =EXYNOS5_GIC_BASE_ADDRESS /* r2 := Exynos5 gic base > address */ > > +kick_cpus_sgi: > > /* send an interrupt */ > > - ldr r0, =(GIC_BASE_ADDRESS + GIC_DR_OFFSET) /* base GICD MMIO > address */ > > + ldr r0, =GIC_DR_OFFSET /* GIC distributor offset > */ > > + add r0, r2 /* r0 := r0 + gic base > address */ > > mov r2, #0x1 > > str r2, [r0, #(GICD_CTLR * 4)] /* enable distributor */ > > mov r2, #0xfe0000 > > @@ -51,13 +69,15 @@ kick_cpus: > > > > /* Get up a CPU into Hyp mode. Clobbers r0-r3. > > * > > - * Expects r12 == CPU number > > + * r5: Machine ID > > + * r12: CPU number > > * > > - * This code is specific to the VE model, and not intended to be used > > + * This code is specific to the VE model/Arndale, and not intended to > be used > > * on production systems. As such it''s a bit hackier than the main > > * boot code in head.S. In future it will be replaced by better > > * integration with the bootloader/firmware so that Xen always starts > > - * in Hyp mode. */ > > + * in Hyp mode. > > + * Clobber r0 - r4 */ > > > > .globl enter_hyp_mode > > enter_hyp_mode: > > @@ -68,33 +88,51 @@ enter_hyp_mode: > > orr r0, r0, #0xb1 /* Set SCD, AW, FW and NS */ > > bic r0, r0, #0xe /* Clear EA, FIQ and IRQ */ > > mcr CP32(r0, SCR) > > + > > + ldr r2, =MACH_TYPE_SMDK5250 /* r4 := Arndale machine ID */ > > + /* By default load Arndale defaults values */ > > + ldr r0, =EXYNOS5_TIMER_FREQUENCY /* r0 := timer''s frequency > */ > > + ldr r1, =EXYNOS5_GIC_BASE_ADDRESS /* r1 := GIC base address */ > > + /* If it''s not the Arndale machine ID, load VE values */ > > + teq r5, r2 > > + ldrne r0, =V2M_TIMER_FREQUENCY > > + ldrne r1, =V2M_GIC_BASE_ADDRESS > > Are these processor or platform specific? If processor can they be > handled like how proc-ca15.S:cortex_a15_init does things? >It''s platform specific.> > > + > > /* Ugly: the system timer''s frequency register is only > > * programmable in Secure state. Since we don''t know where its > > * memory-mapped control registers live, we can''t find out the > > - * right frequency. Use the VE model''s default frequency here. > */ > > - ldr r0, =0x5f5e100 /* 100 MHz */ > > + * right frequency. */ > > mcr CP32(r0, CNTFRQ) > > ldr r0, =0x40c00 /* SMP, c11, c10 in non-secure > mode */ > > mcr CP32(r0, NSACR) > > - mov r0, #GIC_BASE_ADDRESS > > - add r0, r0, #GIC_DR_OFFSET > > + > > + add r0, r1, #GIC_DR_OFFSET > > /* Disable the GIC distributor, on the boot CPU only */ > > - mov r1, #0 > > + mov r4, #0 > > teq r12, #0 /* Is this the boot CPU? */ > > - streq r1, [r0] > > + streq r4, [r0] > > /* Continuing ugliness: Set up the GIC so NS state owns > interrupts, > > * The first 32 interrupts (SGIs & PPIs) must be configured on > all > > * CPUs while the remainder are SPIs and only need to be done > one, on > > * the boot CPU. */ > > add r0, r0, #0x80 /* GICD_IGROUP0 */ > > mov r2, #0xffffffff /* All interrupts to group 1 */ > > - teq r12, #0 /* Boot CPU? */ > > str r2, [r0] /* Interrupts 0-31 (SGI & PPI) */ > > - streq r2, [r0, #4] /* Interrupts 32-63 (SPI) */ > > - streq r2, [r0, #8] /* Interrupts 64-95 (SPI) */ > > + teq r12, #0 /* Boot CPU? */ > > + bne skip_spis /* Don''t route SPIs on secondary > CPUs */ > > + > > + add r4, r1, #GIC_DR_OFFSET > > + ldr r4, [r4, #4] /* r4 := Interrupt Controller > Type Reg */ > > + and r4, r4, #GICD_TYPE_LINES /* r4 := number of SPIs */ > > + /* Assume we have minimum 32 SPIs */ > > It''d be relatively easy to turn this do {} while construct into a > while() {} one and avoid this assumption?I will fix it.> > +1: > > + add r0, r0, #4 /* Go to the new group */ > > + str r2, [r0] /* Update the group */ > > + subs r4, r4, #1 > > + bne 1b > > +skip_spis: > > /* Disable the GIC CPU interface on all processors */ > > - mov r0, #GIC_BASE_ADDRESS > > - add r0, r0, #GIC_CR_OFFSET > > + add r0, r1, #GIC_CR_OFFSET > > mov r1, #0 > > str r1, [r0] > > /* Must drop priority mask below 0x80 before entering NS state > */ > > diff --git a/xen/include/asm-arm/platforms/vexpress.h > b/xen/include/asm-arm/platforms/vexpress.h > > index 5cf3aba..982a293 100644 > > --- a/xen/include/asm-arm/platforms/vexpress.h > > +++ b/xen/include/asm-arm/platforms/vexpress.h > > @@ -32,6 +32,17 @@ > > int vexpress_syscfg(int write, int function, int device, uint32_t > *data); > > #endif > > > > +/* Constants below is only used in assembly because the DTS is not yet > parsed */ > > +#ifdef __ASSEMBLY__ > > + > > +/* GIC base address */ > > +#define V2M_GIC_BASE_ADDRESS 0x2c000000 > > + > > +/* Timer''s frequency */ > > +#define V2M_TIMER_FREQUENCY 0x5f5e100 /* 100 Mhz */ > > + > > +#endif /* __ASSEMBLY__ */ > > + > > #endif /* __ASM_ARM_PLATFORMS_VEXPRESS_H */ > > /* > > * Local variables: >-- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Ian Campbell
2013-Apr-30 12:41 UTC
Re: [RFC 18/29] xen/arm: add generic UART to get the device in the device tree
> Couldn''t it also hardcode a call to a "is this a dt serial > alias" > function? > > > Indeed. Can we assume Xen on Arm will use only one UART? We can modify > the behaviour later.This seems acceptable to me.> > > If I understand your suggestion, you suggest to use > console=myserial > > where *myserial* is the alias on the DTB, right? > > > Right. > > > In this case the name could clash with the hardcoded ones in > Xen that is not good. > > > console=dt:<alias> ? Or to be honest I''m not sure that having > the dt > aliases shadow the Xen hardcoded ones would be a bad thing -- > the x86 > centric com<X> definition hardcoded in Xen is hardly likely to > be useful > on ARM or any DT using platform. > > > I prefer dt:<alias> but how do we parse the configuration for the > UART? > > Do we use dt:<alias>=configuration on the command line? In this case > I don''t see function to retrieve a non-defined parameters on the > command line.Hrm, yes. Perhaps dtuart=, applied to whichever dt:<alias> you choose?> We should also take care about video card. In the future, the devices > will be retrieved from the DTS.In that case perhaps: console=dtuart:<alias> and =dtfb:<alias>? Ian.
Ian Campbell
2013-Apr-30 12:44 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On Tue, 2013-04-30 at 12:21 +0100, Julien Grall wrote:> Missing Xen devel mailing list.Ignore my private reply, I''ve inserted it below...> > Thanks. Even if we gate CONFIG_EARLY_PRINTK to debug=y, we > should let the developper the option to disable/enable early > printk. Otherwise we will lost debug when Xen can boot on > multiple board.I''m not sure I follow, these are both valid debug=y CONFIG_EARLY_PRINTK=pl011 debug=y /* No early printk */ In the latter case you have debug on a system which can boot on multiple boards. Or are you concerned about not being able to build a production (non-debug) hypervisor with early-printk? i.e. debug=n CONFIG_EARLY_PRINTK=pl011 ?
Julien Grall
2013-Apr-30 13:37 UTC
Re: [RFC 18/29] xen/arm: add generic UART to get the device in the device tree
On 04/30/2013 01:41 PM, Ian Campbell wrote:> > >> Couldn''t it also hardcode a call to a "is this a dt serial >> alias" >> function? >> >> >> Indeed. Can we assume Xen on Arm will use only one UART? We can modify >> the behaviour later. > > This seems acceptable to me. >> >> > If I understand your suggestion, you suggest to use >> console=myserial >> > where *myserial* is the alias on the DTB, right? >> >> >> Right. >> >> > In this case the name could clash with the hardcoded ones in >> Xen that is not good. >> >> >> console=dt:<alias> ? Or to be honest I''m not sure that having >> the dt >> aliases shadow the Xen hardcoded ones would be a bad thing -- >> the x86 >> centric com<X> definition hardcoded in Xen is hardly likely to >> be useful >> on ARM or any DT using platform. >> >> >> I prefer dt:<alias> but how do we parse the configuration for the >> UART? >> >> Do we use dt:<alias>=configuration on the command line? In this case >> I don''t see function to retrieve a non-defined parameters on the >> command line. > > Hrm, yes. > > Perhaps dtuart=, applied to whichever dt:<alias> you choose? > >> We should also take care about video card. In the future, the devices >> will be retrieved from the DTS. > > In that case perhaps: console=dtuart:<alias> and =dtfb:<alias>?Sounds good for me. I will rework the patch with that. -- Julien
Julien Grall
2013-Apr-30 13:39 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On 04/30/2013 01:44 PM, Ian Campbell wrote:> On Tue, 2013-04-30 at 12:21 +0100, Julien Grall wrote: >> Missing Xen devel mailing list. > > Ignore my private reply, I''ve inserted it below... > >> >> Thanks. Even if we gate CONFIG_EARLY_PRINTK to debug=y, we >> should let the developper the option to disable/enable early >> printk. Otherwise we will lost debug when Xen can boot on >> multiple board. > > I''m not sure I follow, these are both valid > debug=y CONFIG_EARLY_PRINTK=pl011 > debug=y /* No early printk */ > In the latter case you have debug on a system which can boot on multiple > boards. > > Or are you concerned about not being able to build a production > (non-debug) hypervisor with early-printk? i.e. > debug=n CONFIG_EARLY_PRINTK=pl011 > ?It''s the first one. CONFIG_EARLY_PRINTK should not be enabled on a production build. -- Julien
Ian Campbell
2013-Apr-30 13:51 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On Tue, 2013-04-30 at 14:39 +0100, Julien Grall wrote:> On 04/30/2013 01:44 PM, Ian Campbell wrote: > > > On Tue, 2013-04-30 at 12:21 +0100, Julien Grall wrote: > >> Missing Xen devel mailing list. > > > > Ignore my private reply, I''ve inserted it below... > > > >> > >> Thanks. Even if we gate CONFIG_EARLY_PRINTK to debug=y, we > >> should let the developper the option to disable/enable early > >> printk. Otherwise we will lost debug when Xen can boot on > >> multiple board. > > > > I''m not sure I follow, these are both valid > > debug=y CONFIG_EARLY_PRINTK=pl011 > > debug=y /* No early printk */ > > In the latter case you have debug on a system which can boot on multiple > > boards. > > > > Or are you concerned about not being able to build a production > > (non-debug) hypervisor with early-printk? i.e. > > debug=n CONFIG_EARLY_PRINTK=pl011 > > ? > > It''s the first one. CONFIG_EARLY_PRINTK should not be enabled on a > production build.I''m still confused what your concern is. A build with debug=y is not a production build. Ian.
Julien Grall
2013-Apr-30 13:57 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On 04/30/2013 02:51 PM, Ian Campbell wrote:> On Tue, 2013-04-30 at 14:39 +0100, Julien Grall wrote: >> On 04/30/2013 01:44 PM, Ian Campbell wrote: >> >>> On Tue, 2013-04-30 at 12:21 +0100, Julien Grall wrote: >>>> Missing Xen devel mailing list. >>> >>> Ignore my private reply, I''ve inserted it below... >>> >>>> >>>> Thanks. Even if we gate CONFIG_EARLY_PRINTK to debug=y, we >>>> should let the developper the option to disable/enable early >>>> printk. Otherwise we will lost debug when Xen can boot on >>>> multiple board. >>> >>> I''m not sure I follow, these are both valid >>> debug=y CONFIG_EARLY_PRINTK=pl011 >>> debug=y /* No early printk */ >>> In the latter case you have debug on a system which can boot on multiple >>> boards. >>> >>> Or are you concerned about not being able to build a production >>> (non-debug) hypervisor with early-printk? i.e. >>> debug=n CONFIG_EARLY_PRINTK=pl011 >>> ? >> >> It''s the first one. CONFIG_EARLY_PRINTK should not be enabled on a >> production build. > > I''m still confused what your concern is. > > A build with debug=y is not a production build.I was not sure whether debug=y should imply CONFIG_EARLY_PRINTK or not. Sorry for the misreading. -- Julien
Ian Campbell
2013-Apr-30 14:09 UTC
Re: [RFC 24/29] xen/arm: Don''t use pl011 UART by default for early printk
On Tue, 2013-04-30 at 14:57 +0100, Julien Grall wrote:> On 04/30/2013 02:51 PM, Ian Campbell wrote: > > > On Tue, 2013-04-30 at 14:39 +0100, Julien Grall wrote: > >> On 04/30/2013 01:44 PM, Ian Campbell wrote: > >> > >>> On Tue, 2013-04-30 at 12:21 +0100, Julien Grall wrote: > >>>> Missing Xen devel mailing list. > >>> > >>> Ignore my private reply, I''ve inserted it below... > >>> > >>>> > >>>> Thanks. Even if we gate CONFIG_EARLY_PRINTK to debug=y, we > >>>> should let the developper the option to disable/enable early > >>>> printk. Otherwise we will lost debug when Xen can boot on > >>>> multiple board. > >>> > >>> I''m not sure I follow, these are both valid > >>> debug=y CONFIG_EARLY_PRINTK=pl011 > >>> debug=y /* No early printk */ > >>> In the latter case you have debug on a system which can boot on multiple > >>> boards. > >>> > >>> Or are you concerned about not being able to build a production > >>> (non-debug) hypervisor with early-printk? i.e. > >>> debug=n CONFIG_EARLY_PRINTK=pl011 > >>> ? > >> > >> It''s the first one. CONFIG_EARLY_PRINTK should not be enabled on a > >> production build. > > > > I''m still confused what your concern is. > > > > A build with debug=y is not a production build. > > > I was not sure whether debug=y should imply CONFIG_EARLY_PRINTK or not.Ah, no, rather the other way round -- earlyprintk is allowed only if debug=y. I''m not 100% sure that''s a good idea, no doubt someone will soon come up with an early boot failure which only happens on production builds... Ian.
Julien Grall
2013-Apr-30 15:40 UTC
Re: [RFC 27/29] xen/arm: Add platform specific code for the exynos5
On 04/30/2013 11:00 AM, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> --- >> xen/arch/arm/platforms/Makefile | 1 + >> xen/arch/arm/platforms/exynos5.c | 105 +++++++++++++++++++++++++++++++ >> xen/include/asm-arm/platforms/exynos5.h | 40 ++++++++++++ >> 3 files changed, 146 insertions(+) >> create mode 100644 xen/arch/arm/platforms/exynos5.c >> create mode 100644 xen/include/asm-arm/platforms/exynos5.h >> >> diff --git a/xen/arch/arm/platforms/Makefile b/xen/arch/arm/platforms/Makefile >> index 4313e95..ff2b65b 100644 >> --- a/xen/arch/arm/platforms/Makefile >> +++ b/xen/arch/arm/platforms/Makefile >> @@ -1 +1,2 @@ >> obj-y += vexpress.o >> +obj-y += exynos5.o >> diff --git a/xen/arch/arm/platforms/exynos5.c b/xen/arch/arm/platforms/exynos5.c >> new file mode 100644 >> index 0000000..01e12b7 >> --- /dev/null >> +++ b/xen/arch/arm/platforms/exynos5.c >> @@ -0,0 +1,105 @@ >> +/* >> + * xen/arch/arm/platforms/exynos5.c >> + * >> + * Exynos5 specific settings >> + * >> + * Julien Grall <julien.grall@linaro.org> >> + * Copyright (c) 2013 Linaro Limited. >> + * >> + * 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. >> + */ >> + >> +#include <asm/p2m.h> >> +#include <xen/config.h> >> +#include <xen/device_tree.h> >> +#include <xen/domain_page.h> >> +#include <xen/mm.h> >> +#include <asm/platforms/exynos5.h> >> +#include <asm/platform.h> >> + >> +static int exynos5_init_time(void) >> +{ >> + uint32_t reg; >> + >> + // enable timer on exynos5 arndale board >> + // should probably be done by u-boot > > /* */ please. > >> + reg = platform_read_register(EXYNOS5_MCT_G_TCON); >> + platform_write_register(EXYNOS5_MCT_G_TCON, reg | EXYNOS5_MCT_G_TCON_START); >> + >> + return 0; >> +} >> + >> +/* Additionnal mapping for dom0 (Not in the DTS) */ > > "Additional mappings" > >> +static int exynos5_specific_mapping(struct domain *d) >> +{ >> + paddr_t ma = 0; >> + uint32_t *dst; >> + int res; >> + >> + /* >> + * Set temporary guest traps with 0xe14fff7c which is hvc(0xfffc) >> + * a hyp panic! >> + * TODO: Find why: >> + * 1) Xen abort directly after local_abort_enable when >> + * the p2m_populate_ram is not here. > > It will actually be aborting here somewhere but that abort can''t be > delivered until the point aborts are enabled. My patch "xen: arm: enable > aborts on all physical processors." will enable aborts much earlier so > you might get a better indication of exactly where it goes wrong.My comment is wrong. In fact, I try to map domain memory before the guest page table is loaded on the CPU.>> + * 2) Linux doesn''t start without this trick > > Ouch. I presume it doesn''t actually end up calling hvc 0xfffc? Does it > work if you just map/unmap without writing anything? > > What does Linux do without the trick? Touches address 0x0 perhaps? Would > anything be mapped there on a real Exynos?Not even. (XEN) Guest data abort: Translation fault at level 2 (XEN) gva=40004000 (XEN) gpa=0000000040004000 (XEN) instruction syndrome invalid (XEN) eat=0 cm=0 s1ptw=0 dfsc=6 (XEN) dom0 IPA 0x0000000040004000 (XEN) P2M @ 02ffbfc0 mfn:0xbfdfe (XEN) 1ST[0x1] = 0x00000000bfdfb6ff (XEN) 2ND[0x0] = 0x0000000000000000 (XEN) ----[ Xen-4.3-unstable arm32 debug=y Tainted: C ]---- (XEN) CPU: 0 (XEN) PC: 50008338 (XEN) CPSR: 800001d3 MODE:32-bit Guest SVC (XEN) R0: 40004000 R1: 00000c12 R2: 40008000 R3: 40004000 (XEN) R4: 40008000 R5: 00000000 R6: 0000000e R7: ffffffff (XEN) R8: 501bf8e0 R9: 40000000 R10:50000000 R11:10201105 R12:500080a8 (XEN) USR: SP: 00000000 LR: 00000000 (XEN) SVC: SP: 00000000 LR: 500083cc SPSR:000001d3 (XEN) ABT: SP: 00000000 LR: 00000000 SPSR:00000000 (XEN) UND: SP: 00000000 LR: 00000000 SPSR:00000000 (XEN) IRQ: SP: 00000000 LR: 00000000 SPSR:00000000 (XEN) FIQ: SP: 00000000 LR: 00000000 SPSR:00000000 (XEN) FIQ: R8: 00000000 R9: 00000000 R10:00000000 R11:00000000 R12:00000000 (XEN) (XEN) TTBR0 0000000000 TTBR1 0000000000 TCR 00000000 (XEN) SCTLR 00c50078 (XEN) IFAR 00000000 DFAR 00000000 (XEN) (XEN) HTTBR bfed2000 (XEN) HDFAR 40004000 (XEN) HIFAR 0 (XEN) HPFAR 400040 (XEN) HCR 00002835 (XEN) HSR 90000046 (XEN) VTTBR 10000bfdfe000 (XEN) (XEN) DFSR 0 DFAR 0 (XEN) IFSR 0 IFAR 0 (XEN) (XEN) GUEST STACK GOES HERE (XEN) domain_crash_sync called from traps.c:968 FYI the kernel is loaded at 0x50008000.> I had a weird one running on the v8 foundation model where I had to add > a NOP hypercall to Linux''s head.S before a certain point -- I wonder if > this is related?I did some test and noticed this code is at the wrong place. I didn''t find the issue because with/without this trick linux 3.9 will boot. It''s only happened on the linux 3.7 tree. The code should be done after the kernel is loading in the memory. But I think I should remove this code and patch the kernel. What do you think? By the way, which kernel version do you use? What is your modification?> It''ll be a missing flush or barrier of course, the question is where ;-)Before the unmap_domain_page, right?>> + */ >> + p2m_populate_ram(d, 0x0, 0x1000 - 1); >> + >> + res = gvirt_to_maddr(0, &ma); >> + if ( res ) >> + { >> + printk(XENLOG_ERR "Unable to translate guest address\n"); >> + return -EFAULT; >> + } >> + >> + dst = map_domain_page(ma >> PAGE_SHIFT); >> + dst[2] = 0xe14fff7c; >> + unmap_domain_page(dst); >> + >> + /* Map the chip ID */ >> + map_mmio_regions(d, EXYNOS5_PA_CHIPID, EXYNOS5_PA_CHIPID + PAGE_SIZE - 1, >> + EXYNOS5_PA_CHIPID); >> + >> + /* Map the PWM region */ >> + map_mmio_regions(d, EXYNOS5_PA_TIMER, >> + EXYNOS5_PA_TIMER + (PAGE_SIZE * 2) - 1, >> + EXYNOS5_PA_TIMER); >> + >> + return 0; >> +} >> + >> +static void exynos5_reset(void) >> +{ >> + platform_write_register(EXYNOS5_SWRESET, 1); >> +} >> + >> +static const char const *exynos5_dt_compat[] __initdata >> +{ >> + "samsung,exynos5250", >> + NULL >> +}; >> + >> +PLATFORM_START(exynos5, "SAMSUNG EXYNOS5") >> + .compatible = exynos5_dt_compat, >> + .init_time = exynos5_init_time, >> + .specific_mapping = exynos5_specific_mapping, >> + .reset = exynos5_reset, >> +PLATFORM_END >> + >> +/* >> + * Local variables: >> + * mode: C >> + * c-file-style: "BSD" >> + * c-basic-offset: 4 >> + * indent-tabs-mode: nil >> + * End: >> + */ >> diff --git a/xen/include/asm-arm/platforms/exynos5.h b/xen/include/asm-arm/platforms/exynos5.h >> new file mode 100644 >> index 0000000..d77623c >> --- /dev/null >> +++ b/xen/include/asm-arm/platforms/exynos5.h >> @@ -0,0 +1,40 @@ >> +#ifndef __ASM_ARM_PLATFORMS_EXYNOS5_H >> +#define __ASM_ASM_PLATFORMS_EXYSNO5_H >> + >> +#define EXYNOS5_MCT_BASE 0x101c0000 >> +#define EXYNOS5_MCTREG(x) (EXYNOS5_MCT_BASE + (x)) >> +#define EXYNOS5_MCT_G_TCON EXYNOS5_MCTREG(0x240) >> +#define EXYNOS5_MCT_G_TCON_START (1 << 8) >> + >> +#define EXYNOS5_PA_CHIPID 0x10000000 >> +#define EXYNOS5_PA_TIMER 0x12dd0000 >> +/* Base address of system controller */ >> +#define EXYNOS5_PA_PMU 0x10040000 >> + >> +#define EXYNOS5_SWRESET (EXYNOS5_PA_PMU + 0x0400) >> + >> +#define S5P_PA_SYSRAM 0x02020000 >> + >> +/* Constants below is only used in assembly because the DTS is not yet parsed */ >> +#ifdef __ASSEMBLY__ >> + >> +/* GIC Base Address */ >> +#define EXYNOS5_GIC_BASE_ADDRESS 0x10480000 >> + >> +/* Timer''s frequency */ >> +#define EXYNOS5_TIMER_FREQUENCY (24 * 1000 * 1000) /* 24 MHz */ >> + >> +/* Arndale machine ID */ >> +#define MACH_TYPE_SMDK5250 3774 >> + >> +#endif /* __ASSEMBLY__ */ >> + >> +#endif /* __ASM_ARM_PLATFORMS_EXYNOS5_H */ >> +/* >> + * Local variables: >> + * mode: C >> + * c-file-style: "BSD" >> + * c-basic-offset: 4 >> + * indent-tabs-mode: nil >> + * End: >> + */ > >
Ian Campbell
2013-Apr-30 15:46 UTC
Re: [RFC 27/29] xen/arm: Add platform specific code for the exynos5
On Tue, 2013-04-30 at 16:40 +0100, Julien Grall wrote:> >> + * 2) Linux doesn''t start without this trick > > > > Ouch. I presume it doesn''t actually end up calling hvc 0xfffc? Does it > > work if you just map/unmap without writing anything? > > > > What does Linux do without the trick? Touches address 0x0 perhaps? Would > > anything be mapped there on a real Exynos? > > Not even. > > (XEN) Guest data abort: Translation fault at level 2 > (XEN) gva=40004000 > (XEN) gpa=0000000040004000 > (XEN) instruction syndrome invalid > (XEN) eat=0 cm=0 s1ptw=0 dfsc=6 > (XEN) dom0 IPA 0x0000000040004000 > (XEN) P2M @ 02ffbfc0 mfn:0xbfdfe > (XEN) 1ST[0x1] = 0x00000000bfdfb6ff > (XEN) 2ND[0x0] = 0x0000000000000000 > (XEN) ----[ Xen-4.3-unstable arm32 debug=y Tainted: C ]---- > (XEN) CPU: 0 > (XEN) PC: 50008338 > (XEN) CPSR: 800001d3 MODE:32-bit Guest SVC > (XEN) R0: 40004000 R1: 00000c12 R2: 40008000 R3: 40004000 > (XEN) R4: 40008000 R5: 00000000 R6: 0000000e R7: ffffffff > (XEN) R8: 501bf8e0 R9: 40000000 R10:50000000 R11:10201105 R12:500080a8 > (XEN) USR: SP: 00000000 LR: 00000000 > (XEN) SVC: SP: 00000000 LR: 500083cc SPSR:000001d3 > (XEN) ABT: SP: 00000000 LR: 00000000 SPSR:00000000 > (XEN) UND: SP: 00000000 LR: 00000000 SPSR:00000000 > (XEN) IRQ: SP: 00000000 LR: 00000000 SPSR:00000000 > (XEN) FIQ: SP: 00000000 LR: 00000000 SPSR:00000000 > (XEN) FIQ: R8: 00000000 R9: 00000000 R10:00000000 R11:00000000 R12:00000000 > (XEN) > (XEN) TTBR0 0000000000 TTBR1 0000000000 TCR 00000000 > (XEN) SCTLR 00c50078 > (XEN) IFAR 00000000 DFAR 00000000 > (XEN) > (XEN) HTTBR bfed2000 > (XEN) HDFAR 40004000 > (XEN) HIFAR 0 > (XEN) HPFAR 400040 > (XEN) HCR 00002835 > (XEN) HSR 90000046 > (XEN) VTTBR 10000bfdfe000 > (XEN) > (XEN) DFSR 0 DFAR 0 > (XEN) IFSR 0 IFAR 0 > (XEN) > (XEN) GUEST STACK GOES HERE > (XEN) domain_crash_sync called from traps.c:968 > > FYI the kernel is loaded at 0x50008000.But it is crashing accessing 0x40004000?> > I had a weird one running on the v8 foundation model where I had to add > > a NOP hypercall to Linux''s head.S before a certain point -- I wonder if > > this is related? > > I did some test and noticed this code is at the wrong place. I didn''t > find the issue because with/without this trick linux 3.9 will boot. It''s > only happened on the linux 3.7 tree. > > The code should be done after the kernel is loading in the memory. But I > think I should remove this code and patch the kernel. What do you think?If the kernel is wrong (and you know how!) then you should certainly patch it in preference to adding a hack to the hypervisor.> By the way, which kernel version do you use? What is your modification? > > > It''ll be a missing flush or barrier of course, the question is where ;-) > > > Before the unmap_domain_page, right?I was speculating that your crash was due to a missing barrier *somewhere*, but it doesn''t seem to be the nature of your issue. Ian.
Julien Grall
2013-Apr-30 16:11 UTC
Re: [RFC 27/29] xen/arm: Add platform specific code for the exynos5
On 04/30/2013 04:46 PM, Ian Campbell wrote:> On Tue, 2013-04-30 at 16:40 +0100, Julien Grall wrote: >>>> + * 2) Linux doesn''t start without this trick >>> >>> Ouch. I presume it doesn''t actually end up calling hvc 0xfffc? Does it >>> work if you just map/unmap without writing anything? >>> >>> What does Linux do without the trick? Touches address 0x0 perhaps? Would >>> anything be mapped there on a real Exynos? >> >> Not even. >> >> (XEN) Guest data abort: Translation fault at level 2 >> (XEN) gva=40004000 >> (XEN) gpa=0000000040004000 >> (XEN) instruction syndrome invalid >> (XEN) eat=0 cm=0 s1ptw=0 dfsc=6 >> (XEN) dom0 IPA 0x0000000040004000 >> (XEN) P2M @ 02ffbfc0 mfn:0xbfdfe >> (XEN) 1ST[0x1] = 0x00000000bfdfb6ff >> (XEN) 2ND[0x0] = 0x0000000000000000 >> (XEN) ----[ Xen-4.3-unstable arm32 debug=y Tainted: C ]---- >> (XEN) CPU: 0 >> (XEN) PC: 50008338 >> (XEN) CPSR: 800001d3 MODE:32-bit Guest SVC >> (XEN) R0: 40004000 R1: 00000c12 R2: 40008000 R3: 40004000 >> (XEN) R4: 40008000 R5: 00000000 R6: 0000000e R7: ffffffff >> (XEN) R8: 501bf8e0 R9: 40000000 R10:50000000 R11:10201105 R12:500080a8 >> (XEN) USR: SP: 00000000 LR: 00000000 >> (XEN) SVC: SP: 00000000 LR: 500083cc SPSR:000001d3 >> (XEN) ABT: SP: 00000000 LR: 00000000 SPSR:00000000 >> (XEN) UND: SP: 00000000 LR: 00000000 SPSR:00000000 >> (XEN) IRQ: SP: 00000000 LR: 00000000 SPSR:00000000 >> (XEN) FIQ: SP: 00000000 LR: 00000000 SPSR:00000000 >> (XEN) FIQ: R8: 00000000 R9: 00000000 R10:00000000 R11:00000000 R12:00000000 >> (XEN) >> (XEN) TTBR0 0000000000 TTBR1 0000000000 TCR 00000000 >> (XEN) SCTLR 00c50078 >> (XEN) IFAR 00000000 DFAR 00000000 >> (XEN) >> (XEN) HTTBR bfed2000 >> (XEN) HDFAR 40004000 >> (XEN) HIFAR 0 >> (XEN) HPFAR 400040 >> (XEN) HCR 00002835 >> (XEN) HSR 90000046 >> (XEN) VTTBR 10000bfdfe000 >> (XEN) >> (XEN) DFSR 0 DFAR 0 >> (XEN) IFSR 0 IFAR 0 >> (XEN) >> (XEN) GUEST STACK GOES HERE >> (XEN) domain_crash_sync called from traps.c:968 >> >> FYI the kernel is loaded at 0x50008000. > > But it is crashing accessing 0x40004000? >Right. I will take a look if I can backport a commit from Linux 3.9. Otherwise I will push my Linux 3.9 and dropped 3.7 support for the arndale. -- Julien
Julien Grall
2013-Apr-30 18:04 UTC
Re: [RFC 13/29] xen/arm: Use hierarchical device tree to retrieve GIC information
On 04/30/2013 10:34 AM, Ian Campbell wrote:> On Mon, 2013-04-29 at 21:42 +0100, Julien Grall wrote: >> On 04/29/2013 04:35 PM, Ian Campbell wrote: >> >>> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote: >>>> - Remove early parsing for GIC addresses >>>> - Remove hard coded maintenance IRQ number >>> >>> At last, the payoff! >>> >>>> >>>> Signed-off-by: Julien Grall <julien.grall@linaro.org> >>>> --- >>>> xen/arch/arm/gic.c | 63 ++++++++++++++++++++++++++++------------- >>>> xen/common/device_tree.c | 42 --------------------------- >>> >>> I like this line! >>> >>>> @@ -464,7 +486,7 @@ void gic_route_ppis(void) >>>> { >>>> /* XXX should get these from DT */ >>>> /* GIC maintenance */ >>>> - gic_route_irq(25, 1, 1u << smp_processor_id(), 0xa0); >>>> + gic_route_dt_irq(&gic.maintenance, 1u << smp_processor_id(), 0xa0); >>>> /* Hypervisor Timer */ >>>> gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0); >>>> /* Virtual Timer */ >>>> @@ -813,7 +835,8 @@ void gic_dump_info(struct vcpu *v) >>>> >>>> void __cpuinit init_maintenance_interrupt(void) >>>> { >>>> - request_irq(25, maintenance_interrupt, 0, "irq-maintenance", NULL); >>>> + request_irq(gic.maintenance.irq, maintenance_interrupt, >>>> + 0, "irq-maintenance", NULL); >>> >>> Would a dt_request_irq be useful anywhere other than here? >> >> As all the interrupts should be retrieved from the device_tree could we >> remove request_irq for ARM (ie move request_irq definition to >> asm-x86/irq.h)? It''s also a safe guard for developper to avoid hardcoded >> IRQ. > > Might be something to consider for 4.4, needs discussion with the x86 > chaps and Keir? > > Since request_irq is implerment in arch code we could just skip it, then > link errors would do the rest.What do you mean by "implement in arch code"? Except on UART driver (pl011 and exynos4210) I don''t see any usage in common code. I have also notice that I should create dt_setup_irq. The setup_irq is used in UART driver.>> Then we can: >> 1) modify irq argument type >> 2) rename the function in request_dt_irq >> >> I''m not sure the latter is usefull. >> > >
Ian Campbell
2013-May-01 08:14 UTC
Re: [RFC 13/29] xen/arm: Use hierarchical device tree to retrieve GIC information
> >>> Would a dt_request_irq be useful anywhere other than here? > >> > >> As all the interrupts should be retrieved from the device_tree could we > >> remove request_irq for ARM (ie move request_irq definition to > >> asm-x86/irq.h)? It''s also a safe guard for developper to avoid hardcoded > >> IRQ. > > > > Might be something to consider for 4.4, needs discussion with the x86 > > chaps and Keir? > > > > Since request_irq is implerment in arch code we could just skip it, then > > link errors would do the rest. > > What do you mean by "implement in arch code"?request_irq is implemented in xen/arch/{arm,x86}/irq.c. We could just omit ARMs version (in favour of dt_request_irq), any stray users of request_irq would trigger a linker error...> Except on UART driver > (pl011 and exynos4210) I don''t see any usage in common code. > I have also notice that I should create dt_setup_irq. The setup_irq is > used in UART driver.Sounds wise. Ian.
Stefano Stabellini
2013-May-01 11:51 UTC
Re: [RFC 22/29] xen/arm: Allow Xen to run on multiple platform without recompilation
On Mon, 29 Apr 2013, Julien Grall wrote:> Xen can include various platform support (ie: exynos5, versatile express...) > and choose during boot time a set of callbacks for the current board. > These callbacks will be called in places where each board can have specific > code. For the moment the callbacks are: > - platform_init: additional initialization for the platform > - platform_init_time: some platform (ie: Exynos 5) needs to initialize > the timer with an uncommon way > - platform_specific_mapping: add mapping to dom0 which are not specified > in the device tree > - platform_reset: reset the platformgiven that you added a platform_reset hook, you might as well add a platform_poweroff hook too.> Signed-off-by: Julien Grall <julien.grall@linaro.org> > --- > xen/arch/arm/Makefile | 1 + > xen/arch/arm/domain_build.c | 4 ++ > xen/arch/arm/platform.c | 121 ++++++++++++++++++++++++++++++++++++++++ > xen/arch/arm/setup.c | 3 + > xen/arch/arm/shutdown.c | 2 + > xen/arch/arm/time.c | 6 ++ > xen/arch/arm/xen.lds.S | 6 ++ > xen/include/asm-arm/platform.h | 70 +++++++++++++++++++++++ > 8 files changed, 213 insertions(+) > create mode 100644 xen/arch/arm/platform.c > create mode 100644 xen/include/asm-arm/platform.h > > diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile > index 7a73b79..981ad78 100644 > --- a/xen/arch/arm/Makefile > +++ b/xen/arch/arm/Makefile > @@ -17,6 +17,7 @@ obj-y += p2m.o > obj-y += percpu.o > obj-y += guestcopy.o > obj-y += physdev.o > +obj-y += platform.o > obj-y += setup.o > obj-y += time.o > obj-y += smpboot.o > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > index 11298e1..d6b8086 100644 > --- a/xen/arch/arm/domain_build.c > +++ b/xen/arch/arm/domain_build.c > @@ -12,6 +12,7 @@ > #include <xen/libfdt/libfdt.h> > #include <xen/guest_access.h> > #include <asm/setup.h> > +#include <asm/platform.h> > > #include <asm/gic.h> > #include <xen/irq.h> > @@ -516,6 +517,9 @@ int construct_dom0(struct domain *d) > return rc; > > parse_device_tree(d); > + rc = platform_specific_mapping(d); > + if ( rc < 0 ) > + return rc; > > /* The following loads use the domain''s p2m */ > p2m_load_VTTBR(d); > diff --git a/xen/arch/arm/platform.c b/xen/arch/arm/platform.c > new file mode 100644 > index 0000000..ba569ea > --- /dev/null > +++ b/xen/arch/arm/platform.c > @@ -0,0 +1,121 @@ > +/* > + * xen/arch/arm/platform.c > + * > + * Helpers to execute platform specific code. > + * > + * Julien Grall <julien.grall@linaro.org> > + * Copyright (C) 2013 Linaro Limited. > + * > + * 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. > + */ > + > +#include <asm/platform.h> > +#include <xen/device_tree.h> > +#include <xen/init.h> > + > +extern const struct platform_desc _splatform[], _eplatform[]; > + > +/* Pointer to the current platform description */ > +static const struct platform_desc *platform; > + > + > +static bool_t __init platform_is_compatible(const struct platform_desc *plat) > +{ > + const char *const *compat; > + > + if ( !plat->compatible ) > + return 0; > + > + for ( compat = plat->compatible; *compat; compat++ ) > + { > + if ( dt_machine_is_compatible(*compat) ) > + return 1; > + } > + > + return 0; > +} > + > +/* List of possible platform */ > +static void dump_platform_table(void) > +{ > + const struct platform_desc *p; > + > + printk("Available platform support:\n"); > + > + for ( p = _splatform; p != _eplatform; p++ ) > + printk(" - %s\n", p->name); > +} > + > +int __init platform_init(void) > +{ > + int res = 0; > + > + ASSERT(platform == NULL); > + > + /* Looking for the platform description */ > + for ( platform = _splatform; platform != _eplatform; platform++ ) > + { > + if ( platform_is_compatible(platform) ) > + break; > + } > + > + /* We don''t have specific operations for this platform */ > + if ( platform == _eplatform ) > + { > + /* TODO: List compatible */ > + printk(XENLOG_WARNING "WARNING: Unrecognized/unsupported device tree " > + "compatible list\n"); > + dump_platform_table(); > + platform = NULL; > + } > + else > + printk(XENLOG_INFO "Platform: %s\n", platform->name); > + > + if ( platform && platform->init ) > + res = platform->init(); > + > + return res; > +} > + > +int __init platform_init_time(void) > +{ > + int res = 0; > + > + if ( platform && platform->init_time ) > + res = platform->init_time(); > + > + return res; > +} > + > +int __init platform_specific_mapping(struct domain *d) > +{ > + int res = 0; > + > + if ( platform && platform->specific_mapping ) > + res = platform->specific_mapping(d); > + > + return res; > +} > + > +void platform_reset(void) > +{ > + if ( platform && platform->reset ) > + platform->reset(); > +} > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index aee491d..9721150 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -41,6 +41,7 @@ > #include <asm/early_printk.h> > #include <asm/gic.h> > #include <asm/cpufeature.h> > +#include <asm/platform.h> > > struct cpuinfo_arm __read_mostly boot_cpu_data; > > @@ -439,6 +440,8 @@ void __init start_xen(unsigned long boot_phys_offset, > > processor_id(); > > + platform_init(); > + > init_xen_time(); > > gic_init(); > diff --git a/xen/arch/arm/shutdown.c b/xen/arch/arm/shutdown.c > index c1b60af..a5c2085 100644 > --- a/xen/arch/arm/shutdown.c > +++ b/xen/arch/arm/shutdown.c > @@ -5,6 +5,7 @@ > #include <xen/lib.h> > #include <xen/mm.h> > #include <xen/smp.h> > +#include <asm/platform.h> > > static void raw_machine_reset(void) > { > @@ -21,6 +22,7 @@ static void raw_machine_reset(void) > dsb(); isb(); > clear_fixmap(FIXMAP_MISC); > #endif > + platform_reset(); > } > > static void halt_this_cpu(void *arg) > diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c > index 63dace2..f01be3f 100644 > --- a/xen/arch/arm/time.c > +++ b/xen/arch/arm/time.c > @@ -33,6 +33,7 @@ > #include <asm/time.h> > #include <asm/gic.h> > #include <asm/cpufeature.h> > +#include <asm/platform.h> > > /* > * Unfortunately the hypervisor timer interrupt appears to be buggy in > @@ -130,6 +131,11 @@ int __init init_xen_time(void) > panic("CPU does not support the Generic Timer v1 interface.\n"); > > cpu_khz = READ_SYSREG32(CNTFRQ_EL0) / 1000; > + > + res = platform_init_time(); > + if ( res ) > + return res; > + > boot_count = READ_SYSREG64(CNTPCT_EL0); > printk("Using generic timer at %lu KHz\n", cpu_khz); > > diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S > index 7434e83..b5c99b7 100644 > --- a/xen/arch/arm/xen.lds.S > +++ b/xen/arch/arm/xen.lds.S > @@ -76,6 +76,12 @@ SECTIONS > __lock_profile_end = .; > #endif > > + .arch.info : { > + _splatform = .; > + *(.arch.info) > + _eplatform = .; > + } :text > + > .dev.info : { > _sdevice = .; > *(.dev.info) > diff --git a/xen/include/asm-arm/platform.h b/xen/include/asm-arm/platform.h > new file mode 100644 > index 0000000..c89a4ca > --- /dev/null > +++ b/xen/include/asm-arm/platform.h > @@ -0,0 +1,70 @@ > +#ifndef __ASM_ARM_PLATFORM_H > +#define __ASM_ARM_PLATFORM_H > + > +#include <xen/init.h> > +#include <xen/sched.h> > +#include <xen/mm.h> > + > +/* Describe specific operation for a board */ > +struct platform_desc { > + /* Platform name */ > + const char *name; > + /* Array of device tree ''compatible'' strings */ > + const char *const *compatible; > + /* Platform initialization */ > + int (*init)(void); > + int (*init_time)(void); > + /* Specific mapping for dom0 */ > + int (*specific_mapping)(struct domain *d); > + /* Platform reset */ > + void (*reset)(void); > +}; > + > +int __init platform_init(void); > +int __init platform_init_time(void); > +int __init platform_specific_mapping(struct domain *d); > +void platform_reset(void); > + > +/* Helper to read/write a register */ > +static inline uint32_t platform_read_register(uint32_t addr) > +{ > + volatile const uint32_t *reg; > + uint32_t value; > + > + set_fixmap(FIXMAP_MISC, addr >> PAGE_SHIFT, DEV_SHARED); > + reg = (uint32_t *)(FIXMAP_ADDR(FIXMAP_MISC) + (addr & ~PAGE_MASK)); > + value = *reg; > + dsb(); isb(); > + clear_fixmap(FIXMAP_MISC); > + > + return value; > +} > + > +static inline void platform_write_register(uint32_t addr, uint32_t value) > +{ > + volatile uint32_t *reg; > + > + set_fixmap(FIXMAP_MISC, addr >> PAGE_SHIFT, DEV_SHARED); > + reg = (uint32_t *)(FIXMAP_ADDR(FIXMAP_MISC) + (addr & ~PAGE_MASK)); > + *reg = value; > + clear_fixmap(FIXMAP_MISC); > +} > + > +#define PLATFORM_START(_name, _namestr) \ > +static const struct platform_desc __plat_desc_##_name __used \ > +__attribute__((__section__(".arch.info"))) = { \ > + .name = _namestr, > + > +#define PLATFORM_END \ > +}; > + > +#endif /* __ASM_ARM_PLATFORM_H */ > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > -- > Julien Grall >
Anthony PERARD
2013-May-01 17:17 UTC
Re: [RFC 26/29] xen/arm: Add Exynos 4210 UART support for early printk
On 30/04/13 10:53, Ian Campbell wrote:> On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >> --- >> config/arm32.mk | 1 + >> xen/arch/arm/Rules.mk | 4 ++ >> xen/arch/arm/arm32/Makefile | 1 + >> xen/arch/arm/arm32/debug-exynos5.S | 81 ++++++++++++++++++++++++++++++++++++ >> 4 files changed, 87 insertions(+) >> create mode 100644 xen/arch/arm/arm32/debug-exynos5.S >> >> diff --git a/config/arm32.mk b/config/arm32.mk >> index 593a1d1..01c1490 100644 >> --- a/config/arm32.mk >> +++ b/config/arm32.mk >> @@ -17,6 +17,7 @@ CFLAGS += -marm >> # Possible value: >> # - none: no early printk >> # - pl011: printk with PL011 UART >> +# - exynos5: printk with the second exynos 5 UART > > From the subject I infer that this UART is an Exynos 4210? If so I think > that is the correct name to use here, consistent with the pl011 name > above. (the alternative is that the pl011 is wrong...). > > I suppose in principal a single driver might apply to multiple platforms > but with different base addresses, but that at build time you need to > choose a specific platform, which implies a particular driver. The > current infrastructure doesn''t really express that notion. > > What about if we support a mutually exclusive (enforced only by the > clash of symbols at link time) set of: > CONFIG_EARLY_UART_PL011 > CONFIG_EARLY_UART_EXYNOS4210 > which if defined must be set to the physical address of the port? > > This would mean users need to know the address of the UART on their > platform rather than just being able to name the platform though. > Perhaps that''s a feature not a bug (i.e. they can choose which UART of > multiple UARTs if they want). I suppose we could also support > CONFIG_EARY_UART_PLATFORM=foo and translate into the above. > > Or are there other hardcoded parameters (e.g. crystal rate) which stop > this? >This drivers have been written with the Exynos 5 platform in mind, so I''m not sure it can be called exynos4210. There would be few differences that I can extract from Linux source code, the physical address is different and the few bit to use FIFO are also different but it''s not use here in the early printk. And I''m almost sure the clock stuff would be different on an exynos4. So, in my humble opinion, we should use exynos5 or exynos5250.>> +/* Exynos 5 UART initialization >> + * r11: UART base address >> + * Clobber r0-r1 */ >> +.globl early_uart_init >> +early_uart_init: >> + /* init clock */ >> + ldr r1, =0x10020000 >> + /* select MPLL (800MHz) source clock */ >> + ldr r0, [r1, #0x250] >> + and r0, r0, #(~(0xf<<8)) >> + orr r0, r0, #(0x6<<8) >> + str r0, [r1, #0x250] >> + /* ration 800/(7+1) */ > > What does "ration" mean here? It doesn''t seem to correspond to the > French for denominator, numerator, remainder or ratio (at least not > according to Google Translate ;-))It mean there is a typo ;), someone or something add a N. I suspect it''s something (the keyboard) :). -- Anthony PERARD
Anthony PERARD
2013-May-01 17:24 UTC
Re: [RFC 26/29] xen/arm: Add Exynos 4210 UART support for early printk
On 29/04/13 00:02, Julien Grall wrote:> diff --git a/xen/arch/arm/arm32/debug-exynos5.S b/xen/arch/arm/arm32/debug-exynos5.S > new file mode 100644 > index 0000000..cbe1705 > --- /dev/null > +++ b/xen/arch/arm/arm32/debug-exynos5.S > @@ -0,0 +1,81 @@ > +/* > + * xen/arch/arm/arm32/debug-exynos5.S > + * > + * Exynos 5 specific debug code > + * > + * Copyright (c) 2013 Citrix Systems. > + * > + * 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. > + */ > + > +#include <asm/asm_defns.h> > + > +#define EXYNOS5_UART_BASE_ADDRESS 0x12c20000 > + > +.globl early_uart_paddr > +early_uart_paddr: .word EXYNOS5_UART_BASE_ADDRESS > + > +/* Exynos 5 UART initialization > + * r11: UART base address > + * Clobber r0-r1 */ > +.globl early_uart_init > +early_uart_init: > + /* init clock */ > + ldr r1, =0x10020000 > + /* select MPLL (800MHz) source clock */ > + ldr r0, [r1, #0x250] > + and r0, r0, #(~(0xf<<8)) > + orr r0, r0, #(0x6<<8) > + str r0, [r1, #0x250] > + /* ration 800/(7+1) */ > + ldr r0, [r1, #0x558] > + and r0, r0, #(~(0xf<<8)) > + orr r0, r0, #(0x7<<8) > + str r0, [r1, #0x558] > + > + mov r1, #4 > + str r1, [r11, #0x2c] /* -> UARTIBRD (Baud divisor fraction) */Could you replace UARTIBRD by UFRACVAL? The former is the name for the PL011, and the latter is the name given by the Exynos 5 manual.> + mov r1, #53 > + str r1, [r11, #0x28] /* -> UARTIBRD (Baud divisor integer) */Same here with UBRDIV. -- Anthony PERARD
Ian Campbell
2013-May-02 07:58 UTC
Re: [RFC 26/29] xen/arm: Add Exynos 4210 UART support for early printk
On Wed, 2013-05-01 at 18:17 +0100, Anthony PERARD wrote:> On 30/04/13 10:53, Ian Campbell wrote: > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: > >> --- > >> config/arm32.mk | 1 + > >> xen/arch/arm/Rules.mk | 4 ++ > >> xen/arch/arm/arm32/Makefile | 1 + > >> xen/arch/arm/arm32/debug-exynos5.S | 81 ++++++++++++++++++++++++++++++++++++ > >> 4 files changed, 87 insertions(+) > >> create mode 100644 xen/arch/arm/arm32/debug-exynos5.S > >> > >> diff --git a/config/arm32.mk b/config/arm32.mk > >> index 593a1d1..01c1490 100644 > >> --- a/config/arm32.mk > >> +++ b/config/arm32.mk > >> @@ -17,6 +17,7 @@ CFLAGS += -marm > >> # Possible value: > >> # - none: no early printk > >> # - pl011: printk with PL011 UART > >> +# - exynos5: printk with the second exynos 5 UART > > > > From the subject I infer that this UART is an Exynos 4210? If so I think > > that is the correct name to use here, consistent with the pl011 name > > above. (the alternative is that the pl011 is wrong...). > > > > I suppose in principal a single driver might apply to multiple platforms > > but with different base addresses, but that at build time you need to > > choose a specific platform, which implies a particular driver. The > > current infrastructure doesn''t really express that notion. > > > > What about if we support a mutually exclusive (enforced only by the > > clash of symbols at link time) set of: > > CONFIG_EARLY_UART_PL011 > > CONFIG_EARLY_UART_EXYNOS4210 > > which if defined must be set to the physical address of the port? > > > > This would mean users need to know the address of the UART on their > > platform rather than just being able to name the platform though. > > Perhaps that''s a feature not a bug (i.e. they can choose which UART of > > multiple UARTs if they want). I suppose we could also support > > CONFIG_EARY_UART_PLATFORM=foo and translate into the above. > > > > Or are there other hardcoded parameters (e.g. crystal rate) which stop > > this? > > > > This drivers have been written with the Exynos 5 platform in mind, so > I''m not sure it can be called exynos4210.Maybe I''m confused, I had assumed that exynos4210 was a UART logic block which happened to have been dropped down onto the exynos5 SoC in much the same way that the Cortex-A15 contains several pl011 UART logic blocks. Is this not the case? In exynos5250.dtsi in Linux the UART is described as compatible "samsung,exynos4210-uart", is 4210 actually a previous revision of the Exynos processor which happens to have a compatible UART on it? What I want to avoid is the case where we have dozens of UART drivers which are all identical apart from the fact that they happen to be integrated into a different SoC (all the other Exynos5xxx variants for example), so I''d like to determine the most generic name for this driver possible.> There would be few differences > that I can extract from Linux source code, the physical address is > different and the few bit to use FIFO are also different but it''s not > use here in the early printk. And I''m almost sure the clock stuff would > be different on an exynos4. > > So, in my humble opinion, we should use exynos5 or exynos5250. > > > >> +/* Exynos 5 UART initialization > >> + * r11: UART base address > >> + * Clobber r0-r1 */ > >> +.globl early_uart_init > >> +early_uart_init: > >> + /* init clock */ > >> + ldr r1, =0x10020000 > >> + /* select MPLL (800MHz) source clock */ > >> + ldr r0, [r1, #0x250] > >> + and r0, r0, #(~(0xf<<8)) > >> + orr r0, r0, #(0x6<<8) > >> + str r0, [r1, #0x250] > >> + /* ration 800/(7+1) */ > > > > What does "ration" mean here? It doesn''t seem to correspond to the > > French for denominator, numerator, remainder or ratio (at least not > > according to Google Translate ;-)) > > It mean there is a typo ;), someone or something add a N. I suspect it''s > something (the keyboard) :).I should have thought of that! ;-) Ian.
Anthony PERARD
2013-May-02 10:51 UTC
Re: [RFC 26/29] xen/arm: Add Exynos 4210 UART support for early printk
On 02/05/13 08:58, Ian Campbell wrote:> On Wed, 2013-05-01 at 18:17 +0100, Anthony PERARD wrote: >> > On 30/04/13 10:53, Ian Campbell wrote: >>> > > On Mon, 2013-04-29 at 00:02 +0100, Julien Grall wrote: >>>> > >> --- >>>> > >> config/arm32.mk | 1 + >>>> > >> xen/arch/arm/Rules.mk | 4 ++ >>>> > >> xen/arch/arm/arm32/Makefile | 1 + >>>> > >> xen/arch/arm/arm32/debug-exynos5.S | 81 ++++++++++++++++++++++++++++++++++++ >>>> > >> 4 files changed, 87 insertions(+) >>>> > >> create mode 100644 xen/arch/arm/arm32/debug-exynos5.S >>>> > >> >>>> > >> diff --git a/config/arm32.mk b/config/arm32.mk >>>> > >> index 593a1d1..01c1490 100644 >>>> > >> --- a/config/arm32.mk >>>> > >> +++ b/config/arm32.mk >>>> > >> @@ -17,6 +17,7 @@ CFLAGS += -marm >>>> > >> # Possible value: >>>> > >> # - none: no early printk >>>> > >> # - pl011: printk with PL011 UART >>>> > >> +# - exynos5: printk with the second exynos 5 UART >>> > > >>> > > From the subject I infer that this UART is an Exynos 4210? If so I think >>> > > that is the correct name to use here, consistent with the pl011 name >>> > > above. (the alternative is that the pl011 is wrong...). >>> > > >>> > > I suppose in principal a single driver might apply to multiple platforms >>> > > but with different base addresses, but that at build time you need to >>> > > choose a specific platform, which implies a particular driver. The >>> > > current infrastructure doesn''t really express that notion. >>> > > >>> > > What about if we support a mutually exclusive (enforced only by the >>> > > clash of symbols at link time) set of: >>> > > CONFIG_EARLY_UART_PL011 >>> > > CONFIG_EARLY_UART_EXYNOS4210 >>> > > which if defined must be set to the physical address of the port? >>> > > >>> > > This would mean users need to know the address of the UART on their >>> > > platform rather than just being able to name the platform though. >>> > > Perhaps that''s a feature not a bug (i.e. they can choose which UART of >>> > > multiple UARTs if they want). I suppose we could also support >>> > > CONFIG_EARY_UART_PLATFORM=foo and translate into the above. >>> > > >>> > > Or are there other hardcoded parameters (e.g. crystal rate) which stop >>> > > this? >>> > > >> > >> > This drivers have been written with the Exynos 5 platform in mind, so >> > I''m not sure it can be called exynos4210. > Maybe I''m confused, I had assumed that exynos4210 was a UART logic block > which happened to have been dropped down onto the exynos5 SoC in much > the same way that the Cortex-A15 contains several pl011 UART logic > blocks. Is this not the case?Sorry, I''ve been confused, I did not take close look enough to how the Linux drivers was written, as the manual does not say anything about the history. So yes, I feel better in calling the driver exynos4210, with maybe a different name for the paddr which is exynos5250 specific I suppose.> In exynos5250.dtsi in Linux the UART is described as compatible > "samsung,exynos4210-uart", is 4210 actually a previous revision of the > Exynos processor which happens to have a compatible UART on it?Yes, it seams to be the case, sorry for the confusion.> What I want to avoid is the case where we have dozens of UART drivers > which are all identical apart from the fact that they happen to be > integrated into a different SoC (all the other Exynos5xxx variants for > example), so I''d like to determine the most generic name for this driver > possible.>> > There would be few differences >> > that I can extract from Linux source code, the physical address is >> > different and the few bit to use FIFO are also different but it''s not >> > use here in the early printk. And I''m almost sure the clock stuff would >> > be different on an exynos4. >> > >> > So, in my humble opinion, we should use exynos5 or exynos5250.-- Anthony PERARD