Hi, This is the second version of the patch series. It''s rebased on Xen 4.3 rc-1 with Stefano''s SMP patch series. The majors changes: - Add platform_poweroff and platform_quirks - Rework early assembly printk to use macro instead of function - Use defines where it''s possible in exynos UART code - Missing Signed-off-by from Anthony exynos UART code - Introduce request_dt_irq and setup_dt_irq. request_irq and setup_irq are deprecated for ARM. This part is divided in small patches (one to introduce new function and one to remove the old function) to avoid compilation breakage. For all changes see in each patch. 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 - Convert vtimer to use non-hardcoded IRQ For the moment the known bugs are: - Bash can sometimes crash with: segfault, memory corruption. It''s seems it''s due to a lack of VPF save/restore in Xen. If you want to try this patch series you can clone: git clone -b arm-v2 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. Feel free to test this branch during Xen test day. The wiki has been updated for the arndale board: http://wiki.xen.org/wiki/Xen_ARM_with_Virtualization_Extensions/Arndale It''s now based on: - this patch series for Xen - linux 3.9 Feel free to test this branch during the Xen test day on both the versatile express and the arndale board. Cheers, Anthony PERARD (2): xen/arm: Add exynos 4210 UART support xen/arm: Add Exynos 4210 UART support for early printk Julien Grall (31): 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: Introduce setup_dt_irq xen/arm: Introduce request_dt_irq 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: Allow Xen to run on multiple platform without recompilation xen/arm: WORKAROUND 1:1 memory mapping for dom0 xen/arm: Add versatile express platform xen/arm: remove request_irq xen/arm: remove setup_irq xen/arm: Don''t use pl011 UART by default for early printk xen/arm: Add platform specific code for the exynos5 xen/arm: WORKAROUND Support kick cpus and switch to hypervisor for the exynos5 xen/arm64: Remove hardcoded value for gic in assembly code config/arm32.mk | 1 + docs/misc/arm/early-printk.txt | 15 + xen/arch/arm/Makefile | 4 +- xen/arch/arm/Rules.mk | 19 + xen/arch/arm/arm32/Makefile | 4 +- xen/arch/arm/arm32/debug-exynos4210.inc | 77 ++ xen/arch/arm/arm32/debug-pl011.inc | 58 ++ xen/arch/arm/arm32/debug.S | 33 + xen/arch/arm/arm32/head.S | 84 +- xen/arch/arm/arm32/mode_switch.S | 75 +- xen/arch/arm/arm64/Makefile | 2 + xen/arch/arm/arm64/debug-pl011.inc | 59 ++ xen/arch/arm/arm64/debug.S | 33 + xen/arch/arm/arm64/head.S | 71 +- xen/arch/arm/arm64/mode_switch.S | 7 +- xen/arch/arm/device.c | 74 ++ xen/arch/arm/domain_build.c | 192 ++++- xen/arch/arm/early_printk.c | 19 +- xen/arch/arm/gic.c | 160 +++- xen/arch/arm/irq.c | 8 +- xen/arch/arm/platform.c | 137 +++ xen/arch/arm/platforms/Makefile | 1 + xen/arch/arm/platforms/exynos5.c | 86 ++ xen/arch/arm/platforms/vexpress.c | 30 + xen/arch/arm/setup.c | 14 +- xen/arch/arm/shutdown.c | 16 +- xen/arch/arm/time.c | 65 +- xen/arch/arm/vgic.c | 20 +- xen/arch/arm/vpl011.c | 4 +- xen/arch/arm/xen.lds.S | 14 + xen/common/device_tree.c | 1326 ++++++++++++++++++++++++++++-- xen/drivers/char/Makefile | 2 + xen/drivers/char/arm-uart.c | 81 ++ xen/drivers/char/exynos4210-uart.c | 357 ++++++++ xen/drivers/char/pl011.c | 64 +- xen/drivers/char/serial.c | 16 + xen/include/asm-arm/config.h | 15 +- 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/exynos4210-uart.h | 111 +++ xen/include/asm-arm/gic.h | 16 +- xen/include/asm-arm/irq.h | 8 + xen/include/asm-arm/platform.h | 87 ++ 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 | 378 ++++++++- xen/include/xen/serial.h | 13 +- 49 files changed, 3682 insertions(+), 292 deletions(-) create mode 100644 docs/misc/arm/early-printk.txt create mode 100644 xen/arch/arm/arm32/debug-exynos4210.inc create mode 100644 xen/arch/arm/arm32/debug-pl011.inc create mode 100644 xen/arch/arm/arm32/debug.S create mode 100644 xen/arch/arm/arm64/debug-pl011.inc 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/exynos4210-uart.c create mode 100644 xen/include/asm-arm/device.h create mode 100644 xen/include/asm-arm/exynos4210-uart.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-May-08 02:33 UTC
[PATCH V2 01/33] xen/arm: lr must be included in range [0-nr_lr(
Signed-off-by: Julien Grall <julien.grall@linaro.org> Acked-by: Ian Campbell <ian.campbell@citrix.com> Changes in v2: - Typo in the commit message --- 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 61de230..6d71aae 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-May-08 02:33 UTC
[PATCH V2 02/33] 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> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- 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-May-08 02:33 UTC
[PATCH V2 03/33] xen/arm: Remove duplicated GICD_ICPIDR2 definition
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 84ebc83..3efb2b5 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-May-08 02:33 UTC
[PATCH V2 04/33] 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> Changes in v2: - Move buffer to a static variable --- xen/arch/arm/early_printk.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c index bdf4c0e..0f99a43 100644 --- a/xen/arch/arm/early_printk.c +++ b/xen/arch/arm/early_printk.c @@ -29,6 +29,9 @@ void __init early_putch(char c) *r = c; } +/* Early printk buffer */ +static char __initdata buf[512]; + static void __init early_puts(const char *s) { while (*s != ''\0'') { @@ -41,8 +44,6 @@ static void __init early_puts(const char *s) static void __init early_vprintk(const char *fmt, va_list args) { - char buf[80]; - vsnprintf(buf, sizeof(buf), fmt, args); early_puts(buf); } -- Julien Grall
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 05/33] 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> 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 -- 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> 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 8748272..6581492 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
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 07/33] xen/arm: Create a hierarchical device tree
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> Changes in v2: - s/dom0$/device/ in comment "By default dom0 owns the dom0" - Use DOMID_XEN instead of DOMID_INVALID for DT_USED_BY_XEN --- 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 59646d6..07c0444 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -429,12 +429,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..bdf8871 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 device */ + 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..8f526d1 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_XEN + +/** + * 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-May-08 02:33 UTC
[PATCH V2 08/33] xen/arm: Add helpers to use the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - use dt_node_cmp and dt_compat_cmp in early device tree code --- xen/common/device_tree.c | 127 ++++++++++++++++++++++++++++++++++++++++- xen/include/xen/device_tree.h | 120 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+), 2 deletions(-) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index bdf8871..449c332 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -88,20 +88,23 @@ bool_t device_tree_type_matches(const void *fdt, int node, const char *match) if ( prop == NULL ) return 0; - return !strcmp(prop, match); + return !dt_node_cmp(prop, match); } bool_t device_tree_node_compatible(const void *fdt, int node, const char *match) { int len, l; + int mlen; const void *prop; + mlen = strlen(match); + prop = fdt_getprop(fdt, node, "compatible", &len); if ( prop == NULL ) return 0; while ( len > 0 ) { - if ( !strcmp(prop, match) ) + if ( !dt_compat_cmp(prop, match, mlen) ) return 1; l = strlen(prop) + 1; prop += l; @@ -573,6 +576,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 +635,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 8f526d1..879b75d 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-May-08 02:33 UTC
[PATCH V2 09/33] 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 449c332..8d37018 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; @@ -707,6 +735,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 879b75d..ce34ba5 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-May-08 02:33 UTC
[PATCH V2 10/33] xen/arm: Add helpers to retrieve an interrupt description from the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - Move interrupt type from xen/irq.h to xen/device_tree.h - Prefix all defines by DT_ --- xen/common/device_tree.c | 362 +++++++++++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 130 +++++++++++++++ 2 files changed, 492 insertions(+) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 8d37018..e5ff779 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 @@ -1020,6 +1023,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; @@ -1051,6 +1129,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 @@ -1392,6 +1738,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 ce34ba5..bf873d9 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -101,6 +101,67 @@ struct dt_device_node { }; +/** + * IRQ line type. + * + * DT_IRQ_TYPE_NONE - default, unspecified type + * DT_IRQ_TYPE_EDGE_RISING - rising edge triggered + * DT_IRQ_TYPE_EDGE_FALLING - falling edge triggered + * DT_IRQ_TYPE_EDGE_BOTH - rising and falling edge triggered + * DT_IRQ_TYPE_LEVEL_HIGH - high level triggered + * DT_IRQ_TYPE_LEVEL_LOW - low level triggered + * DT_IRQ_TYPE_LEVEL_MASK - Mask to filter out the level bits + * DT_IRQ_TYPE_SENSE_MASK - Mask for all the above bits + */ +#define DT_IRQ_TYPE_NONE 0x00000000 +#define DT_IRQ_TYPE_EDGE_RISING 0x00000001 +#define DT_IRQ_TYPE_EDGE_FALLING 0x00000002 +#define DT_IRQ_TYPE_EDGE_BOTH \ + (DT_IRQ_TYPE_EDGE_FALLING | DT_IRQ_TYPE_EDGE_RISING) +#define DT_IRQ_TYPE_LEVEL_HIGH 0x00000004 +#define DT_IRQ_TYPE_LEVEL_LOW 0x00000008 +#define DT_IRQ_TYPE_LEVEL_MASK \ + (DT_IRQ_TYPE_LEVEL_LOW | DT_IRQ_TYPE_LEVEL_HIGH) +#define DT_IRQ_TYPE_SENSE_MASK 0x0000000f + +/** + * dt_irq - describe an IRQ in the device tree + * @irq: IRQ number + * @type: IRQ type (see DT_IRQ_TYPE_*) + * + * This structure is returned when an interrupt is mapped. + */ +struct dt_irq { + unsigned int irq; + unsigned int type; +}; + +/* If type == DT_IRQ_TYPE_NONE, assume we use level triggered */ +static inline bool_t dt_irq_is_level_trigger(const struct dt_irq *irq) +{ + unsigned int type = irq->type; + + return (type & DT_IRQ_TYPE_LEVEL_MASK) || (type == DT_IRQ_TYPE_NONE); +} + +/** + * 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 +203,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 +381,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 +399,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 * -- 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> Changes in v2: - Use dt_irq_is_level_trigger instead of the old name irq_is_level_trigger --- 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 6d71aae..b9fbe3d 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 = dt_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 3efb2b5..78dd21a 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); @@ -142,6 +144,9 @@ extern void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq,int virtual); extern void vgic_clear_pending_irqs(struct vcpu *v); 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> Changes in v2: - Use DT_IRQ_TYPE_SENSE_MASK instead of IRQ_TYPE_SENSE_MASK --- 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 b9fbe3d..78fc144 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] & DT_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 07c0444..e4228f7 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -430,6 +430,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 78dd21a..6ff217c 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -189,6 +189,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
This function will replace setup_irq in later patch. It takes a dt_irq as first argument instead of an unsigned int. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 5 +++++ xen/include/asm-arm/irq.h | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 78fc144..1efa9a3 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -521,6 +521,11 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq, return 0; } +int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new) +{ + return setup_irq(irq->irq, new); +} + int __init setup_irq(unsigned int irq, struct irqaction *new) { int rc; diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h index 9fc008c..47399ca 100644 --- a/xen/include/asm-arm/irq.h +++ b/xen/include/asm-arm/irq.h @@ -2,6 +2,7 @@ #define _ASM_HW_IRQ_H #include <xen/config.h> +#include <xen/device_tree.h> #define NR_VECTORS 256 /* XXX */ @@ -25,6 +26,7 @@ struct irq_cfg { #define nr_static_irqs NR_IRQS struct irq_desc; +struct irqaction; struct irq_desc *__irq_to_desc(int irq); @@ -37,6 +39,8 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, int is_fiq); void init_IRQ(void); void init_secondary_IRQ(void); +int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new); + #endif /* _ASM_HW_IRQ_H */ /* * Local variables: -- Julien Grall
This function will replace request_irq in a later patch. It takes a dt_irq as first argument instead of an unsigned int. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/irq.c | 7 +++++++ xen/include/asm-arm/irq.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c index 8c96a0a..0b7a75f 100644 --- a/xen/arch/arm/irq.c +++ b/xen/arch/arm/irq.c @@ -93,6 +93,13 @@ void __cpuinit init_secondary_IRQ(void) BUG_ON(init_local_irq_data() < 0); } +int __init request_dt_irq(const struct dt_irq *irq, + void (*handler)(int, void *, struct cpu_user_regs *), + unsigned long irqflags, const char *devname, void *dev_id) +{ + return request_irq(irq->irq, handler, irqflags, devname, dev_id); +} + int __init request_irq(unsigned int irq, void (*handler)(int, void *, struct cpu_user_regs *), unsigned long irqflags, const char * devname, void *dev_id) diff --git a/xen/include/asm-arm/irq.h b/xen/include/asm-arm/irq.h index 47399ca..248398d 100644 --- a/xen/include/asm-arm/irq.h +++ b/xen/include/asm-arm/irq.h @@ -39,6 +39,10 @@ void do_IRQ(struct cpu_user_regs *regs, unsigned int irq, int is_fiq); void init_IRQ(void); void init_secondary_IRQ(void); +int __init request_dt_irq(const struct dt_irq *irq, + void (*handler)(int, void *, struct cpu_user_regs *), + unsigned long irqflags, const char *devname, + void *dev_id); int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new); #endif /* _ASM_HW_IRQ_H */ -- Julien Grall
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 15/33] 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> Changes in v2: - use the new function request_dt_irq --- 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 1efa9a3..34304b3 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; /* Number of interrupts (SPIs + PPIs + SGIs) */ + 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 */ @@ -830,7 +852,8 @@ void gic_dump_info(struct vcpu *v) void __cpuinit init_maintenance_interrupt(void) { - request_irq(25, maintenance_interrupt, 0, "irq-maintenance", NULL); + request_dt_irq(&gic.maintenance, maintenance_interrupt, + 0, "irq-maintenance", NULL); } /* diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index e5ff779..548d21b 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -425,46 +425,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) @@ -516,8 +476,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 bf873d9..deef5e7 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-May-08 02:33 UTC
[PATCH V2 16/33] xen/arm: Retrieve timer interrupts from the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - Hardcode ppi_nr value - Use the new function request_dt_irq --- 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 34304b3..91348b6 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..bfc41c2 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 = 0, + PHYS_NONSECURE_PPI = 1, + VIRT_PPI = 2, + HYP_PPI = 3, + MAX_TIMER_PPI = 4, +}; + +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_dt_irq(&timer_irq[HYP_PPI], timer_interrupt, 0, "hyptimer", NULL); + request_dt_irq(&timer_irq[VIRT_PPI], vtimer_interrupt, 0, + "virtimer", NULL); + request_dt_irq(&timer_irq[PHYS_NONSECURE_PPI], 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
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 17/33] xen/arm: Don''t hardcode VGIC informations
- 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> Acked-by: Ian Campbell <ian.campbell@citrix.com> Changes in v2: - Don''t use javadoc style --- xen/arch/arm/gic.c | 21 ++++++++++++++++++--- xen/arch/arm/vgic.c | 20 ++++++++++++++------ xen/include/asm-arm/domain.h | 5 ++++- xen/include/asm-arm/gic.h | 3 +++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 91348b6..715db60 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]; @@ -771,11 +776,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 f9c1a6b..7eaccb7 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -30,8 +30,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 */ @@ -80,7 +78,15 @@ 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 @@ -163,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 ) @@ -440,7 +446,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; @@ -620,7 +626,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 cca7416..cb251cc 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -88,13 +88,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 6ff217c..e7608dc 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -189,6 +189,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-May-08 02:33 UTC
[PATCH V2 18/33] xen/arm: Introduce a generic way to use a device from the device tree
Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - Add missing ALIGN in xen.lds.S --- xen/arch/arm/Makefile | 1 + xen/arch/arm/device.c | 74 ++++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/xen.lds.S | 7 ++++ xen/include/asm-arm/device.h | 52 +++++++++++++++++++++++++++++ 4 files changed, 134 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 8f75044..4955a21 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -28,6 +28,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..deab040 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -76,6 +76,13 @@ SECTIONS __lock_profile_end = .; #endif + . = ALIGN(8); + .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-May-08 02:33 UTC
[PATCH V2 19/33] 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 routes 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> Changes in v2: - Improve commit message --- 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 715db60..d719229 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-May-08 02:33 UTC
[PATCH V2 20/33] 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 dtuart=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> Changes in v2: - Use dtuart parameter instead of com1. The first one is more arm while the latter is more x86 --- xen/arch/arm/setup.c | 3 +- xen/drivers/char/Makefile | 1 + xen/drivers/char/arm-uart.c | 81 ++++++++++++++++++++++++++++++++++++++++++ xen/drivers/char/serial.c | 6 ++++ xen/include/asm-arm/config.h | 2 +- xen/include/xen/serial.h | 7 ++++ 6 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 xen/drivers/char/arm-uart.c diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index e4228f7..7b2df8b 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -435,8 +435,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..c76875e --- /dev/null +++ b/xen/drivers/char/arm-uart.c @@ -0,0 +1,81 @@ +/* + * 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 UART port with a string: + * alias + * + * @alias: alias used in the device tree for the UART + * TODO: Implement config in each UART driver. + */ +static char __initdata opt_dtuart[30] = ""; +string_param("dtuart", opt_dtuart); + +void __init arm_uart_init(void) +{ + struct dt_device_node *dev; + int ret; + u64 addr, size; + struct serial_arm_defaults defaults; + const char *devalias = opt_dtuart; + + if ( !console_has("dtuart") || !strcmp(opt_dtuart, "") ) + { + early_printk("No console\n"); + return; + } + + early_printk("Looking for UART console %s\n", devalias); + dev = dt_find_node_by_alias(devalias); + + if ( !dev ) + { + early_printk("Unable to find device \"%s\"\n", devalias); + return; + } + + /* TODO: Handle UART with 0 or multiple base address */ + 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/drivers/char/serial.c b/xen/drivers/char/serial.c index 0ae7e4d..c4c4a84 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -271,6 +271,12 @@ int __init serial_parse_handle(char *conf) goto common; } + if ( !strncmp(conf, "dtuart", 5) ) + { + handle = SERHND_COM1; + goto common; + } + if ( strncmp(conf, "com", 3) ) goto fail; diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h index 98a3a43..8ed72f5 100644 --- a/xen/include/asm-arm/config.h +++ b/xen/include/asm-arm/config.h @@ -39,7 +39,7 @@ #define CONFIG_VIDEO 1 -#define OPT_CONSOLE_STR "com1" +#define OPT_CONSOLE_STR "dtuart" #ifdef MAX_PHYS_CPUS #define NR_CPUS MAX_PHYS_CPUS diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 5de5171..f548f8b 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,12 @@ 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-May-08 02:33 UTC
[PATCH V2 21/33] 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> Changes in v2: - Rework TODO - Use the new function setup_dt_irq --- xen/arch/arm/gic.c | 4 --- xen/arch/arm/setup.c | 4 --- xen/drivers/char/pl011.c | 64 ++++++++++++++++++++++++++++++++++++---------- xen/include/xen/serial.h | 1 - 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index d719229..f7b9889 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 7b2df8b..d8a3578 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -432,10 +432,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..03161c4 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_dt_irq(&uart->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,56 @@ 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) +/* TODO: Parse UART config from the command line */ +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 f548f8b..16ed261 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-May-08 02:33 UTC
[PATCH V2 22/33] 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> Changes in v2: - Use the new function dt_irq_is_level_trigger - Disable DEBUG_DT by default - Rename parse_device_tree to map_device_from_device_tree --- 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 6581492..0b762a9 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 map_device_from_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"); + map_device_from_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 f7b9889..ddad0c8 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -692,13 +692,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) @@ -706,6 +707,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); @@ -713,9 +715,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 = dt_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 e7608dc..513c1fc 100644 --- a/xen/include/asm-arm/gic.h +++ b/xen/include/asm-arm/gic.h @@ -157,7 +157,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-May-08 02:33 UTC
[PATCH V2 23/33] 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 - platform_poweroff: poweroff the platform - platform_quirks: list of quirks for a specific board. Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - add platform_poweroff - add platform_quirks --- xen/arch/arm/Makefile | 1 + xen/arch/arm/domain_build.c | 4 ++ xen/arch/arm/platform.c | 137 ++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/setup.c | 3 + xen/arch/arm/shutdown.c | 2 + xen/arch/arm/time.c | 6 ++ xen/arch/arm/xen.lds.S | 7 ++ xen/include/asm-arm/platform.h | 81 ++++++++++++++++++++++++ 8 files changed, 241 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 4955a21..2717f26 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -18,6 +18,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 0b762a9..89e3ab3 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> @@ -511,6 +512,9 @@ int construct_dom0(struct domain *d) return rc; map_device_from_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..b621f3a --- /dev/null +++ b/xen/arch/arm/platform.c @@ -0,0 +1,137 @@ +/* + * 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(); +} + +void platform_poweroff(void) +{ + if ( platform && platform->poweroff ) + platform->poweroff(); +} + +bool_t platform_has_quirk(uint32_t quirk) +{ + uint32_t quirks = 0; + + if ( platform && platform->quirks ) + quirks = platform->quirks(); + + return !!(quirks & quirk); +} + +/* + * 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 d8a3578..a81b146 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -42,6 +42,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; @@ -440,6 +441,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 61b5280..0903842 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 bfc41c2..1114fe7 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 deab040..3b60668 100644 --- a/xen/arch/arm/xen.lds.S +++ b/xen/arch/arm/xen.lds.S @@ -77,6 +77,13 @@ SECTIONS #endif . = ALIGN(8); + .arch.info : { + _splatform = .; + *(.arch.info) + _eplatform = .; + } :text + + . = ALIGN(8); .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..17e4bd5 --- /dev/null +++ b/xen/include/asm-arm/platform.h @@ -0,0 +1,81 @@ +#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); + /* Platform power-off */ + void (*poweroff)(void); + /* + * Platform quirks + * Defined has a function because a platform can support multiple + * board with different quirk on each + */ + uint32_t (*quirks)(void); +}; + +int __init platform_init(void); +int __init platform_init_time(void); +int __init platform_specific_mapping(struct domain *d); +void platform_reset(void); +void platform_poweroff(void); +bool_t platform_has_quirk(uint32_t quirk); + + +/* 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
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 24/33] 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> Changes in v2: - Add quirk in platform code to only enable 1:1 mapping if the board really need it to run (ie: SYS MMU is not yet implemented in Xen). --- xen/arch/arm/domain_build.c | 41 ++++++++++++++++++++++++++++++++++++++++ xen/include/asm-arm/platform.h | 6 ++++++ 2 files changed, 47 insertions(+) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 89e3ab3..6774033 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -62,6 +62,43 @@ struct vcpu *__init alloc_dom0_vcpu0(void) return alloc_vcpu(dom0, 0, 0); } +static int set_memory_reg_11(struct domain *d, struct kernel_info *kinfo, + const void *fdt, const u32 *cell, int len, + int address_cells, int size_cells, u32 *new_cell) +{ + int reg_size = (address_cells + size_cells) * sizeof(*cell); + paddr_t start; + paddr_t size; + struct page_info *pg; + unsigned int order = get_order_from_bytes(dom0_mem); + int res; + paddr_t spfn; + + 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); + + 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 set_memory_reg(struct domain *d, struct kernel_info *kinfo, const void *fdt, const u32 *cell, int len, int address_cells, int size_cells, u32 *new_cell) @@ -71,6 +108,10 @@ static int set_memory_reg(struct domain *d, struct kernel_info *kinfo, u64 start; u64 size; + if ( platform_has_quirk(PLATFORM_QUIRK_DOM0_MAPPING_11) ) + return set_memory_reg_11(d, kinfo, fdt, cell, len, address_cells, + size_cells, new_cell); + while ( kinfo->unassigned_mem > 0 && l + reg_size <= len && kinfo->mem.nr_banks < NR_MEM_BANKS ) { diff --git a/xen/include/asm-arm/platform.h b/xen/include/asm-arm/platform.h index 17e4bd5..436bde1 100644 --- a/xen/include/asm-arm/platform.h +++ b/xen/include/asm-arm/platform.h @@ -28,6 +28,12 @@ struct platform_desc { uint32_t (*quirks)(void); }; +/* + * Quirk to map dom0 memory in 1:1 + * Usefull on platform where System MMU is not yet implemented + */ +#define PLATFORM_QUIRK_DOM0_MAPPING_11 (1 << 0) + int __init platform_init(void); int __init platform_init_time(void); int __init platform_specific_mapping(struct domain *d); -- Julien Grall
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 25/33] xen/arm: Add versatile express platform
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> Changes in v2: - Add TODO to retrieve reset base address in the DT --- xen/arch/arm/platforms/vexpress.c | 30 ++++++++++++++++++++++++++++++ xen/arch/arm/shutdown.c | 14 -------------- xen/include/asm-arm/config.h | 3 --- xen/include/asm-arm/platforms/vexpress.h | 3 +++ 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/xen/arch/arm/platforms/vexpress.c b/xen/arch/arm/platforms/vexpress.c index fd4ce74..c51abf2 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 @@ -91,6 +92,35 @@ out: } /* + * TODO: Get base address from the device tree + * See arm,vexpress-reset node + */ +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 * c-file-style: "BSD" diff --git a/xen/arch/arm/shutdown.c b/xen/arch/arm/shutdown.c index 0903842..767cc12 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 8ed72f5..7599202 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
All calls to this function in ARM code have been removed. This function SHOULD not be used. If someone calls this function, a linking error will occur. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/irq.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c index 0b7a75f..0fbd3d1 100644 --- a/xen/arch/arm/irq.c +++ b/xen/arch/arm/irq.c @@ -97,13 +97,6 @@ int __init request_dt_irq(const struct dt_irq *irq, void (*handler)(int, void *, struct cpu_user_regs *), unsigned long irqflags, const char *devname, void *dev_id) { - return request_irq(irq->irq, handler, irqflags, devname, dev_id); -} - -int __init request_irq(unsigned int irq, - void (*handler)(int, void *, struct cpu_user_regs *), - unsigned long irqflags, const char * devname, void *dev_id) -{ struct irqaction *action; int retval; @@ -113,7 +106,7 @@ int __init request_irq(unsigned int irq, * which interrupt is which (messes up the interrupt freeing * logic etc). */ - if (irq >= nr_irqs) + if (irq->irq >= nr_irqs) return -EINVAL; if (!handler) return -EINVAL; @@ -127,7 +120,7 @@ int __init request_irq(unsigned int irq, action->dev_id = dev_id; action->free_on_release = 1; - retval = setup_irq(irq, action); + retval = setup_dt_irq(irq, action); if (retval) xfree(action); -- Julien Grall
All calls to this function in ARM code have been removed. This function SHOULD not be used. If someone calls this function, a linking error will occur. Signed-off-by: Julien Grall <julien.grall@linaro.org> --- xen/arch/arm/gic.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index ddad0c8..08602dd 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -553,20 +553,15 @@ static int __setup_irq(struct irq_desc *desc, unsigned int irq, int __init setup_dt_irq(const struct dt_irq *irq, struct irqaction *new) { - return setup_irq(irq->irq, new); -} - -int __init setup_irq(unsigned int irq, struct irqaction *new) -{ int rc; unsigned long flags; struct irq_desc *desc; - desc = irq_to_desc(irq); + desc = irq_to_desc(irq->irq); spin_lock_irqsave(&desc->lock, flags); - rc = __setup_irq(desc, irq, new); + rc = __setup_irq(desc, irq->irq, new); spin_unlock_irqrestore(&desc->lock, flags); -- Julien Grall
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 28/33] 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 assembly macro/define: - EALY_UART_BASE_ADDRESS: 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.inc comments. Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - Use macro instead of function for assembly early printk API - Add documentation for ARM early printk --- docs/misc/arm/early-printk.txt | 14 +++++++ xen/arch/arm/Makefile | 2 +- xen/arch/arm/Rules.mk | 15 ++++++++ xen/arch/arm/arm32/Makefile | 5 ++- xen/arch/arm/arm32/debug-pl011.inc | 58 +++++++++++++++++++++++++++++ xen/arch/arm/arm32/debug.S | 33 +++++++++++++++++ xen/arch/arm/arm32/head.S | 65 ++++++++++++++++----------------- xen/arch/arm/arm64/Makefile | 2 + xen/arch/arm/arm64/debug-pl011.inc | 59 ++++++++++++++++++++++++++++++ xen/arch/arm/arm64/debug.S | 33 +++++++++++++++++ xen/arch/arm/arm64/head.S | 71 ++++++++++++++++-------------------- xen/arch/arm/early_printk.c | 16 +------- xen/include/asm-arm/config.h | 2 - xen/include/asm-arm/early_printk.h | 2 +- 14 files changed, 284 insertions(+), 93 deletions(-) create mode 100644 docs/misc/arm/early-printk.txt create mode 100644 xen/arch/arm/arm32/debug-pl011.inc create mode 100644 xen/arch/arm/arm32/debug.S create mode 100644 xen/arch/arm/arm64/debug-pl011.inc create mode 100644 xen/arch/arm/arm64/debug.S diff --git a/docs/misc/arm/early-printk.txt b/docs/misc/arm/early-printk.txt new file mode 100644 index 0000000..4065811 --- /dev/null +++ b/docs/misc/arm/early-printk.txt @@ -0,0 +1,14 @@ +How to enable early printk + +Early printk can only be enabled if debug=y. You may want to enable it 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. + +CONFIG_EARLY_PRINTK=mach +where mach is the name of the machine: + - vexpress: printk with pl011 for versatile express + +By default early printk is disabled. diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 2717f26..87fabe1 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 += psci.o diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk index a0a14e0..4af052c 100644 --- a/xen/arch/arm/Rules.mk +++ b/xen/arch/arm/Rules.mk @@ -36,3 +36,18 @@ endif ifneq ($(call cc-option,$(CC),-fvisibility=hidden,n),n) CFLAGS += -DGCC_HAS_VISIBILITY_ATTRIBUTE endif + +EARLY_PRINTK := n + +ifeq ($(debug),y) + +# Early printk for versatile express +# TODO handle UART base address from make command line +ifeq ($(CONFIG_EARLY_PRINTK), vexpress) +EARLY_PRINTK := y +EARLY_PRINTK_INC := pl011 +endif + +CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK +CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK_INC=\"debug-$(EARLY_PRINTK_INC).inc\" +endif 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.inc b/xen/arch/arm/arm32/debug-pl011.inc new file mode 100644 index 0000000..6954aeb --- /dev/null +++ b/xen/arch/arm/arm32/debug-pl011.inc @@ -0,0 +1,58 @@ +/* + * xen/arch/arm/arm32/debug-pl011.inc + * + * 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. + */ + +#define EARLY_UART_BASE_ADDRESS 0x1c090000 + +/* PL011 UART initialization + * rb: register which contains the UART base address + * rc: scratch register 1 + * rd: scratch register 2 (unused here) */ +.macro early_uart_init rb, rc, rd + mov \rc, #0x0 + str \rc, [\rb, #0x28] /* -> UARTFBRD (Baud divisor fraction) */ + mov \rc, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */ + str \rc, [\rb, #0x24] /* -> UARTIBRD (Baud divisor integer) */ + mov \rc, #0x60 /* 8n1 */ + str \rc, [\rb, #0x2C] /* -> UARTLCR_H (Line control) */ + ldr \rc, =0x00000301 /* RXE | TXE | UARTEN */ + str \rc, [\rb, #0x30] /* -> UARTCR (Control Register) */ +.endm + +/* PL011 UART wait UART to be ready to transmit + * rb: register which contains the UART base address + * rc: scratch register */ +.macro early_uart_ready rb, rc +1: + ldr \rc, [\rb, #0x18] /* <- UARTFR (Flag register) */ + tst \rc, #0x8 /* Check BUSY bit */ + bne 1b /* Wait for the UART to be ready */ +.endm + +/* PL011 UART transmit character + * rb: register which contains the UART base address + * rt: register which contains the character to transmit */ +.macro early_uart_transmit rb, rt + str \rt, [\rb] /* -> UARTDR (Data Register) */ +.endm + +/* + * 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..09e5cae --- /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> + +#ifdef EARLY_PRINTK_INC +#include EARLY_PRINTK_INC +#endif + +.globl early_putch +/* Print a character on the UART - this function is called by C + * r0: character to print */ +early_putch: + ldr r1, =FIXMAP_ADDR(FIXMAP_CONSOLE) /* r1 := VA UART base address */ + early_uart_ready r1, r2 + early_uart_transmit r1, r0 + mov pc, lr diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S index 0b4cfde..df71a31 100644 --- a/xen/arch/arm/arm32/head.S +++ b/xen/arch/arm/arm32/head.S @@ -32,9 +32,13 @@ #define PT_UPPER(x) (PT_##x & 0xf00) #define PT_LOWER(x) (PT_##x & 0x0ff) +#if (defined (EARLY_PRINTK)) && (defined (EARLY_PRINTK_INC)) +#include EARLY_PRINTK_INC +#endif + /* 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 +46,9 @@ 98: .asciz _s ; \ .align 2 ; \ 99: -#else +#else /* EARLY_PRINTK */ #define PRINT(s) -#endif +#endif /* !EARLY_PRINTK */ .arm @@ -106,8 +110,8 @@ past_zImage: bne 1b boot_cpu: -#ifdef EARLY_UART_ADDRESS - ldr r11, =EARLY_UART_ADDRESS /* r11 := UART base address */ +#ifdef EARLY_PRINTK + ldr r11, =EARLY_UART_BASE_ADDRESS /* r11 := UART base address */ teq r12, #0 /* CPU 0 sets up the UART too */ bleq init_uart PRINT("- CPU ") @@ -216,7 +220,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 +283,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,49 +349,42 @@ fail: PRINT("- Boot failed -\r\n") 1: wfe b 1b -#ifdef EARLY_UART_ADDRESS -/* Bring up the UART. Specific to the PL011 UART. +#ifdef EARLY_PRINTK +/* Bring up the UART. + * r11: Early UART base address * Clobbers r0-r2 */ 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) */ + early_uart_init r11, r1, r2 adr r0, 1f - b puts + b puts /* 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 */ + * r11: Early UART base address + * Clobber r1 */ puts: - ldr r2, [r11, #0x18] /* <- UARTFR (Flag register) */ - tst r2, #0x8 /* Check BUSY bit */ - bne puts /* Wait for the UART to be ready */ - ldrb r2, [r0], #1 /* Load next char */ - teq r2, #0 /* Exit on nul */ + early_uart_ready r11, r1 + ldrb r1, [r0], #1 /* Load next char */ + teq r1, #0 /* Exit on nul */ moveq pc, lr - str r2, [r11] /* -> UARTDR (Data Register) */ - b puts + early_uart_transmit r11, r1 + b puts /* Print a 32-bit number in hex. Specific to the PL011 UART. * r0: Number to print. - * clobbers r0-r3 */ + * r11: Early UART base address + * clobbers r1-r3 */ putn: 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: + early_uart_ready r11, r2 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) */ + early_uart_transmit r11, r2 lsl r0, #4 /* Roll it through one nybble at a time */ subs r3, r3, #1 bne 1b @@ -396,7 +393,7 @@ putn: hex: .ascii "0123456789abcdef" .align 2 -#else /* EARLY_UART_ADDRESS */ +#else /* EARLY_PRINTK */ init_uart: .global early_puts @@ -404,7 +401,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..9484548 100644 --- a/xen/arch/arm/arm64/Makefile +++ b/xen/arch/arm/arm64/Makefile @@ -5,3 +5,5 @@ obj-y += mode_switch.o obj-y += traps.o obj-y += domain.o + +obj-$(EARLY_PRINTK) += debug.o diff --git a/xen/arch/arm/arm64/debug-pl011.inc b/xen/arch/arm/arm64/debug-pl011.inc new file mode 100644 index 0000000..ee6e0e0 --- /dev/null +++ b/xen/arch/arm/arm64/debug-pl011.inc @@ -0,0 +1,59 @@ +/* + * 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 EARLY_UART_BASE_ADDRESS 0x1c090000 + +/* PL011 UART initialization + * xb: register which containts the UART base address + * c: scratch register number */ +.macro early_uart_init xb, c + mov x\c, #0x0 + strh w\c, [\xb, #0x28] /* -> UARTFBRD (Baud divisor fraction) */ + mov x\c, #0x4 /* 7.3728MHz / 0x4 == 16 * 115200 */ + strh w\c, [\xb, #0x24] /* -> UARTIBRD (Baud divisor integer) */ + mov x\c, #0x60 /* 8n1 */ + str w\c, [\xb, #0x2C] /* -> UARTLCR_H (Line control) */ + ldr x\c, =0x00000301 /* RXE | TXE | UARTEN */ + str w\c, [\xb, #0x30] /* -> UARTCR (Control Register) */ +.endm + +/* PL011 UART wait UART to be ready to transmit + * xb: register which contains the UART base address + * c: scratch register number */ +.macro early_uart_ready xb, c +1: + ldrh w\c, [\xb, #0x18] /* <- UARTFR (Flag register) */ + tst w\c, #0x8 /* Check BUSY bit */ + b.ne 1b /* Wait for the UART to be ready */ +.endm + +/* PL011 UART transmit character + * xb: register which contains the UART base address + * wt: register which contains the character to transmit */ +.macro early_uart_transmit xb, wt + strb \wt, [\xb] /* -> UARTDR (Data Register) */ +.endm + +/* + * 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..48a6567 --- /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> + +#ifdef EARLY_PRINTK_INC +#include EARLY_PRINTK_INC +#endif + +.globl early_putch +/* Print a character on the UART - this function is called by C + * x0: character to print */ +early_putch: + ldr x23, =FIXMAP_ADDR(FIXMAP_CONSOLE) + early_uart_ready x23, 1 + early_uart_transmit x23, w0 + ret diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S index ef02899..df58471 100644 --- a/xen/arch/arm/arm64/head.S +++ b/xen/arch/arm/arm64/head.S @@ -29,9 +29,13 @@ #define PT_DEV 0xe71 /* nG=1 AF=1 SH=10 AP=01 NS=1 ATTR=100 T=0 P=1 */ #define PT_DEV_L3 0xe73 /* nG=1 AF=1 SH=10 AP=01 NS=1 ATTR=100 T=1 P=1 */ +#if (defined (EARLY_PRINTK)) && (defined (EARLY_PRINTK_INC)) +#include EARLY_PRINTK_INC +#endif + /* 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 +43,9 @@ 98: .asciz _s ; \ .align 2 ; \ 99: -#else +#else /* EARLY_PRINTK */ #define PRINT(s) -#endif +#endif /* !EARLY_PRINTK */ /*.aarch64*/ @@ -109,8 +113,8 @@ real_start: 2: boot_cpu: -#ifdef EARLY_UART_ADDRESS - ldr x23, =EARLY_UART_ADDRESS /* x23 := UART base address */ +#ifdef EARLY_PRINTK + ldr x23, =EARLY_UART_BASE_ADDRESS /* x23 := UART base address */ cbnz x22, 1f bl init_uart /* CPU 0 sets up the UART too */ 1: PRINT("- CPU ") @@ -206,7 +210,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 +217,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 +268,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,51 +329,44 @@ 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. + * x23: Early UART base address + * Clobbers x0-x1 */ 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) */ + early_uart_init x23, 0 adr x0, 1f - b puts + b puts /* 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. + * x23: Early UART base address + * Clobber x1 */ puts: - ldrh w2, [x23, #0x18] /* <- UARTFR (Flag register) */ - tst w2, #0x8 /* Check BUSY bit */ - b.ne puts /* Wait for the UART to be ready */ - ldrb w2, [x0], #1 /* Load next char */ - cbz w2, 1f /* Exit on nul */ - str w2, [x23] /* -> UARTDR (Data Register) */ + early_uart_ready x23, 1 + ldrb w1, [x0], #1 /* Load next char */ + cbz w1, 1f /* Exit on nul */ + early_uart_transmit x23, w1 b puts 1: ret /* Print a 32-bit number in hex. Specific to the PL011 UART. - * r0: Number to print. - * clobbers r0-r3 */ + * x0: Number to print. + * x23: Early UART base address + * clobbers x1-x3 */ putn: 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: + early_uart_ready x23, 2 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) */ + early_uart_transmit x23, w2 lsl x0, x0, #4 /* Roll it through one nybble at a time */ subs x3, x3, #1 b.ne 1b @@ -382,7 +375,7 @@ putn: hex: .ascii "0123456789abcdef" .align 2 -#else /* EARLY_UART_ADDRESS */ +#else /* EARLY_PRINTK */ init_uart: .global early_puts @@ -390,4 +383,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 0f99a43..5950323 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); /* Early printk buffer */ static char __initdata buf[512]; @@ -68,5 +56,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 7599202..6414c89 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
From: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - Use defines where it''s possible - Move UART definition in a separate header. Will be used for early UART - Replace all // by /* ... */ - Add Anthony as first author --- config/arm32.mk | 1 + xen/drivers/char/Makefile | 1 + xen/drivers/char/exynos4210-uart.c | 357 +++++++++++++++++++++++++++++++++ xen/include/asm-arm/exynos4210-uart.h | 111 ++++++++++ 4 files changed, 470 insertions(+) create mode 100644 xen/drivers/char/exynos4210-uart.c create mode 100644 xen/include/asm-arm/exynos4210-uart.h diff --git a/config/arm32.mk b/config/arm32.mk index f64f0c1..d8e958b 100644 --- a/config/arm32.mk +++ b/config/arm32.mk @@ -8,6 +8,7 @@ CONFIG_ARM_$(XEN_OS) := y CFLAGS += -marm HAS_PL011 := y +HAS_EXYNOS4210 := 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..0edd103 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_EXYNOS4210) += exynos4210-uart.o obj-$(HAS_EHCI) += ehci-dbgp.o obj-$(CONFIG_ARM) += arm-uart.o obj-y += serial.o diff --git a/xen/drivers/char/exynos4210-uart.c b/xen/drivers/char/exynos4210-uart.c new file mode 100644 index 0000000..5cde0f6 --- /dev/null +++ b/xen/drivers/char/exynos4210-uart.c @@ -0,0 +1,357 @@ +/* + * xen/drivers/char/exynos4210-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> +#include <asm/exynos4210-uart.h> + +static struct exynos4210_uart { + unsigned int baud, clock_hz, data_bits, parity, stop_bits; + struct dt_irq irq; + volatile unsigned char *regs; + struct irqaction irqaction; +} exynos4210_com[2] = {{0}}; + +/* 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 inline uint32_t exynos4210_read(const struct exynos4210_uart *uart, + size_t offset) +{ + return *(uint32_t *)(uart->regs + offset); +} + +static inline void exynos4210_write(const struct exynos4210_uart *uart, + size_t offset, uint32_t value) +{ + *(uint32_t *)(uart->regs + offset) = value; +} + +static void exynos4210_uart_interrupt(int irq, void *data, struct cpu_user_regs *regs) +{ + struct serial_port *port = data; + struct exynos4210_uart *uart = port->uart; + unsigned int status; + + status = exynos4210_read(uart, UINTP); + + while ( status != 0 ) + { + /* Clear all pending interrupts + * but should take care of ERROR and MODEM + */ + + if ( status & UINTM_ERROR ) + { + uint32_t error_bit; + + error_bit = exynos4210_read(uart, UERSTAT); + + if ( error_bit & UERSTAT_OVERRUN ) + dprintk(XENLOG_ERR, "uart: overrun error\n"); + if ( error_bit & UERSTAT_PARITY ) + dprintk(XENLOG_ERR, "uart: parity error\n"); + if ( error_bit & UERSTAT_FRAME ) + dprintk(XENLOG_ERR, "uart: frame error\n"); + if ( error_bit & UERSTAT_BREAK ) + dprintk(XENLOG_ERR, "uart: break detected\n"); + /* Clear error pending interrupt */ + exynos4210_write(uart, UINTP, UINTM_ERROR); + } + + + if ( status & (UINTM_RXD | UINTM_ERROR) ) + { + /* uart->regs[UINTM] |= RXD|ERROR; */ + serial_rx_interrupt(port, regs); + /* uart->regs[UINTM] &= ~(RXD|ERROR); */ + exynos4210_write(uart, UINTP, UINTM_RXD | UINTM_ERROR); + } + + if ( status & (UINTM_TXD | UINTM_MODEM) ) + { + /* uart->regs[UINTM] |= TXD|MODEM; */ + serial_tx_interrupt(port, regs); + /* uart->regs[UINTM] &= ~(TXD|MODEM); */ + exynos4210_write(uart, UINTP, UINTM_TXD | UINTM_MODEM); + } + + status = exynos4210_read(uart, UINTP); + } +} + +static void __init exynos4210_uart_init_preirq(struct serial_port *port) +{ + struct exynos4210_uart *uart = port->uart; + unsigned int divisor; + uint32_t ulcon; + + /* reset, TX/RX disables */ + exynos4210_write(uart, UCON, 0); + + /* No Interrupt, auto flow control */ + exynos4210_write(uart, UMCON, 0); + + /* Line control and baud-rate generator. */ + if ( uart->baud != BAUD_AUTO ) + { + /* Baud rate specified: program it into the divisor latch. */ + divisor = ((uart->clock_hz) / (uart->baud)) - 1; + /* FIXME: will use a hacked divisor, assuming the src clock and bauds */ + exynos4210_write(uart, UFRACVAL, 53); + exynos4210_write(uart, UBRDIV, 4); + } + else + { + /* TODO: should be updated */ + /* Baud rate already set: read it out from the divisor latch. */ +#if 0 + divisor = (uart->regs[IBRD] << 6) | uart->regs[FBRD]; + uart->baud = (uart->clock_hz << 2) / divisor; +#endif + } + + /* + * Number of bits per character + * 0 => 5 bits + * 1 => 6 bits + * 2 => 7 bits + * 3 => 8 bits + */ + ASSERT(uart->data_bits >= 5 && uart->data_bits <= 8); + ulcon = (uart->data_bits - 5); + + /* + * Stop bits + * 0 => 1 stop bit per frame + * 1 => 2 stop bit per frame + */ + ASSERT(uart->stop_bits >= 1 && uart->stop_bits <= 2); + ulcon |= (uart->stop_bits - 1) << ULCON_STOPB_SHIFT; + + + /* Parity */ + ulcon |= uart->parity << ULCON_PARITY_SHIFT; + + exynos4210_write(uart, ULCON, ulcon); + + /* Mask and clear the interrupts */ + exynos4210_write(uart, UINTM, UINTM_ALLI); + exynos4210_write(uart, UINTP, UINTM_ALLI); + + /* reset FIFO */ + exynos4210_write(uart, UFCON, UFCON_FIFO_RESET); + + /* TODO: Add timeout to avoid infinite loop */ + while ( exynos4210_read(uart, UFCON) & UFCON_FIFO_RESET ) + ; + + /* + * Enable FIFO and set the trigger level of Tx FIFO + * The trigger level is always set to b101, an interrupt will be + * generated when data count of Tx FIFO is less than or equal to the + * following value: + * UART0 => 160 bytes + * UART1 => 40 bytes + * UART2 => 10 bytes + * UART3 => 10 bytes + */ + exynos4210_write(uart, UFCON, UFCON_FIFO_TX_TRIGGER | UFCON_FIFO_EN); + + /* + * Enable the UART for Rx and Tx + * - Use only interrupt request + * - Interrupts are level trigger + * - Enable Rx timeout + */ + exynos4210_write(uart, UCON, + UCON_RX_IRQ_LEVEL | UCON_TX_IRQ_LEVEL | UCON_RX_IRQ | + UCON_TX_IRQ | UCON_RX_TIMEOUT); +} + +static void __init exynos4210_uart_init_postirq(struct serial_port *port) +{ + struct exynos4210_uart *uart = port->uart; + int rc; + + uart->irqaction.handler = exynos4210_uart_interrupt; + uart->irqaction.name = "exynos4210_uart"; + uart->irqaction.dev_id = port; + + if ( (rc = setup_dt_irq(&uart->irq, &uart->irqaction)) != 0 ) + dprintk(XENLOG_ERR, "Failed to allocated exynos4210_uart IRQ %d\n", + uart->irq.irq); + + /* Unmask interrupts */ + exynos4210_write(uart, UINTM, ~UINTM_ALLI); + + /* Clear pending interrupts */ + exynos4210_write(uart, UINTP, UINTM_ALLI); + + /* Enable interrupts */ + exynos4210_write(uart, UMCON, exynos4210_read(uart, UMCON) | UMCON_INT_EN); +} + +static void exynos4210_uart_suspend(struct serial_port *port) +{ + BUG(); // XXX +} + +static void exynos4210_uart_resume(struct serial_port *port) +{ + BUG(); // XXX +} + +static unsigned int exynos4210_uart_tx_ready(struct serial_port *port) +{ + struct exynos4210_uart *uart = port->uart; + + /* Tx fifo full ? */ + if ( exynos4210_read(uart, UFSTAT) & UFSTAT_TX_FULL ) + return 0; + else + { + uint32_t val = exynos4210_read(uart, UFSTAT); + + val = (val & UFSTAT_TX_COUNT_MASK) >> UFSTAT_TX_COUNT_SHIFT; + + /* XXX: Here we assume that we use UART 2/3, on the others + * UART the buffer is bigger + */ + ASSERT(val >= 0 && val <= FIFO_MAX_SIZE); + + return (FIFO_MAX_SIZE - val); + } +} + +static void exynos4210_uart_putc(struct serial_port *port, char c) +{ + struct exynos4210_uart *uart = port->uart; + + exynos4210_write(uart, UTXH, (uint32_t)(unsigned char)c); +} + +static int exynos4210_uart_getc(struct serial_port *port, char *pc) +{ + struct exynos4210_uart *uart = port->uart; + uint32_t ufstat = exynos4210_read(uart, UFSTAT); + uint32_t count; + + count = (ufstat & UFSTAT_RX_COUNT_MASK) >> UFSTAT_RX_COUNT_SHIFT; + + /* Check if Rx fifo is full or if the is something in it */ + if ( ufstat & UFSTAT_RX_FULL || count ) + { + *pc = exynos4210_read(uart, URXH) & URXH_DATA_MASK; + return 1; + } + else + return 0; +} + +static int __init exynos4210_uart_irq(struct serial_port *port) +{ + struct exynos4210_uart *uart = port->uart; + + return uart->irq.irq; +} + +static const struct dt_irq __init *exynos4210_uart_dt_irq(struct serial_port *port) +{ + struct exynos4210_uart *uart = port->uart; + + return &uart->irq; +} + +static struct uart_driver __read_mostly exynos4210_uart_driver = { + .init_preirq = exynos4210_uart_init_preirq, + .init_postirq = exynos4210_uart_init_postirq, + .endboot = NULL, + .suspend = exynos4210_uart_suspend, + .resume = exynos4210_uart_resume, + .tx_ready = exynos4210_uart_tx_ready, + .putc = exynos4210_uart_putc, + .getc = exynos4210_uart_getc, + .irq = exynos4210_uart_irq, + .dt_irq_get = exynos4210_uart_dt_irq, +}; + +static int __init exynos4210_uart_init(struct dt_device_node *dev, + const void *data) +{ + const struct serial_arm_defaults *defaults = data; + struct exynos4210_uart *uart; + int res; + + if ( (defaults->index < 0) || (defaults->index > 1) ) + return -EINVAL; + + uart = &exynos4210_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 = (unsigned char *)defaults->register_base_address; + + res = dt_device_get_irq(dev, 0, &uart->irq); + if ( res ) + { + early_printk("exynos4210: Unable to retrieve the IRQ\n"); + return res; + } + + /* Register with generic serial driver. */ + serial_register_uart(uart - exynos4210_com, &exynos4210_uart_driver, uart); + + dt_device_set_used_by(dev, DT_USED_BY_XEN); + + return 0; +} + +static const char const *exynos4210_dt_compat[] __initdata +{ + "samsung,exynos4210-uart", + NULL +}; + +DT_DEVICE_START(exynos4210, "Exynos 4210 UART", DEVICE_SERIAL) + .compatible = exynos4210_dt_compat, + .init = exynos4210_uart_init, +DT_DEVICE_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/exynos4210-uart.h b/xen/include/asm-arm/exynos4210-uart.h new file mode 100644 index 0000000..1527521 --- /dev/null +++ b/xen/include/asm-arm/exynos4210-uart.h @@ -0,0 +1,111 @@ +/* + * xen/include/asm-arm/exynos4210-uart.h + * + * Common constant definition between ealry printk and the UART driver + * for the exynos 4210 UART + * + * 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. + */ + +#ifndef __ASM_ARM_EXYNOS4210_H +#define __ASM_ARM_EXYNOS4210_H + + +/* + * this value is only valid for UART 2 and UART 3 + * XXX: define per UART + */ +#define FIFO_MAX_SIZE 16 + +/* register addresses */ +#define ULCON (0x00) +#define UCON (0x04) +#define UFCON (0x08) +#define UMCON (0x0c) +#define UTRSTAT (0x10) +#define UERSTAT (0x14) +#define UFSTAT (0x18) +#define UMSTAT (0x1c) +#define UTXH (0x20) +#define URXH (0x24) +#define UBRDIV (0x28) +#define UFRACVAL (0x2c) +#define UINTP (0x30) +#define UINTS (0x34) +#define UINTM (0x38) + +/* UCON */ +#define UCON_RX_IRQ (1 << 0) +#define UCON_TX_IRQ (1 << 2) +#define UCON_RX_TIMEOUT (1 << 7) + +/* + * FIXME: IRQ_LEVEL should be 1 << n but with this value, the IRQ + * handler will never end... + */ +#define UCON_RX_IRQ_LEVEL (0 << 8) +#define UCON_TX_IRQ_LEVEL (0 << 9) + +/* ULCON */ +#define ULCON_STOPB_SHIFT 2 +#define ULCON_PARITY_SHIFT 3 + +/* UFCON */ +#define UFCON_FIFO_TX_RESET (1 << 2) +#define UFCON_FIFO_RX_RESET (1 << 1) +#define UFCON_FIFO_RESET (UFCON_FIFO_TX_RESET | UFCON_FIFO_RX_RESET) +#define UFCON_FIFO_EN (1 << 0) + +#define UFCON_FIFO_TX_TRIGGER (0x6 << 8) + +/* UMCON */ +#define UMCON_INT_EN (1 << 3) + +/* UERSTAT */ +#define UERSTAT_OVERRUN (1 << 0) +#define UERSTAT_PARITY (1 << 1) +#define UERSTAT_FRAME (1 << 2) +#define UERSTAT_BREAK (1 << 3) + +/* UFSTAT */ +#define UFSTAT_TX_FULL (1 << 24) +#define UFSTAT_TX_COUNT_SHIFT (16) +#define UFSTAT_TX_COUNT_MASK (0xff << UFSTAT_TX_COUNT_SHIFT) +#define UFSTAT_RX_FULL (1 << 8) +#define UFSTAT_RX_COUNT_SHIFT (0) +#define UFSTAT_RX_COUNT_MASK (0xff << UFSTAT_RX_COUNT_SHIFT) + +/* UTRSTAT */ +#define UTRSTAT_TX_EMPTY (1 << 1) + +/* URHX */ +#define URXH_DATA_MASK (0xff) + +/* Interrupt bits (UINTP, UINTS, UINTM) */ +#define UINTM_MODEM (1 << 3) +#define UINTM_TXD (1 << 2) +#define UINTM_ERROR (1 << 1) +#define UINTM_RXD (1 << 0) +#define UINTM_ALLI (UINTM_MODEM | UINTM_TXD | UINTM_ERROR | UINTM_RXD) + +#endif /* __ASM_ARM_EXYNOS4210_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- Julien Grall
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 30/33] xen/arm: Add Exynos 4210 UART support for early printk
From: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - Use assembly macro instead of function - Add Anthony as first author --- docs/misc/arm/early-printk.txt | 1 + xen/arch/arm/Rules.mk | 4 ++ xen/arch/arm/arm32/Makefile | 1 - xen/arch/arm/arm32/debug-exynos4210.inc | 77 +++++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 xen/arch/arm/arm32/debug-exynos4210.inc diff --git a/docs/misc/arm/early-printk.txt b/docs/misc/arm/early-printk.txt index 4065811..d5cae85 100644 --- a/docs/misc/arm/early-printk.txt +++ b/docs/misc/arm/early-printk.txt @@ -10,5 +10,6 @@ option should not be enable for Xens that are intended to be portable. CONFIG_EARLY_PRINTK=mach where mach is the name of the machine: - vexpress: printk with pl011 for versatile express + - exynos5250: printk with the second UART By default early printk is disabled. diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk index 4af052c..cff834e 100644 --- a/xen/arch/arm/Rules.mk +++ b/xen/arch/arm/Rules.mk @@ -47,6 +47,10 @@ ifeq ($(CONFIG_EARLY_PRINTK), vexpress) EARLY_PRINTK := y EARLY_PRINTK_INC := pl011 endif +ifeq ($(CONFIG_EARLY_PRINTK), exynos5250) +EARLY_PRINTK := y +EARLY_PRINTK_INC := exynos4210 +endif CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK_INC=\"debug-$(EARLY_PRINTK_INC).inc\" diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile index 6af8ca3..aaf277a 100644 --- a/xen/arch/arm/arm32/Makefile +++ b/xen/arch/arm/arm32/Makefile @@ -8,4 +8,3 @@ 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/arm32/debug-exynos4210.inc b/xen/arch/arm/arm32/debug-exynos4210.inc new file mode 100644 index 0000000..17ee5f1 --- /dev/null +++ b/xen/arch/arm/arm32/debug-exynos4210.inc @@ -0,0 +1,77 @@ +/* + * xen/arch/arm/arm32/debug-exynos4210.inc + * + * 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/exynos4210-uart.h> + +#define EARLY_UART_BASE_ADDRESS 0x12c20000 + +/* Exynos 5 UART initialization + * rb: register which containts the UART base address + * rc: scratch register 1 + * rd: scratch register 2 */ +.macro early_uart_init rb rc rd + /* init clock */ + ldr \rc, =0x10020000 + /* select MPLL (800MHz) source clock */ + ldr \rd, [\rc, #0x250] + and \rd, \rd, #(~(0xf<<8)) + orr \rd, \rd, #(0x6<<8) + str \rd, [\rc, #0x250] + /* ratio 800/(7+1) */ + ldr \rd, [\rc, #0x558] + and \rd, \rd, #(~(0xf<<8)) + orr \rd, \rd, #(0x7<<8) + str \rd, [\rc, #0x558] + + mov \rc, #4 + str \rc, [\rb, #UFRACVAL] /* -> UFRACVAL (Baud divisor fraction) */ + mov \rc, #53 + str \rc, [\rb, #UBRDIV] /* -> UBRDIV (Baud divisor integer) */ + mov \rc, #3 /* 8n1 */ + str \rc, [\rb, #ULCON] /* -> (Line control) */ + ldr \rc, =UCON_TX_IRQ /* TX IRQMODE */ + str \rc, [\rb, #UCON] /* -> (Control Register) */ + mov \rc, #0x0 + str \rc, [\rb, #UFCON] /* disable FIFO */ + mov \rc, #0x0 + str \rc, [\rb, #UMCON] /* no auto flow control */ +.endm + +/* Exynos 5 UART wait UART to be ready to transmit + * rb: register which containts the UART base address + * rc: scratch register */ +.macro early_uart_ready rb rc +1: + ldr \rc, [\rb, #UTRSTAT] /* <- UTRSTAT (Flag register) */ + tst \rc, #UTRSTAT_TX_EMPTY /* Check BUSY bit */ + beq 1b /* Wait for the UART to be ready */ +.endm + +/* Exynos 5 UART transmit character + * rb: register which containts the UART base address + * rt: register which containts the character to transmit */ +.macro early_uart_transmit rb rt + str \rt, [\rb, #UTXH] /* -> UTXH (Data Register) */ +.endm + +/* + * Local variables: + * mode: ASM + * indent-tabs-mode: nil + * End: + */ -- Julien Grall
Julien Grall
2013-May-08 02:33 UTC
[PATCH V2 31/33] xen/arm: Add platform specific code for the exynos5
Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - Add dom0 1:1 mapping quirk for the arndale board - s/mapping/mappings/ in comment - Remove debug trap (unnecessary with linux 3.9) --- xen/arch/arm/platforms/Makefile | 1 + xen/arch/arm/platforms/exynos5.c | 86 +++++++++++++++++++++++++++++++ xen/include/asm-arm/platforms/exynos5.h | 40 ++++++++++++++ 3 files changed, 127 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..8620390 --- /dev/null +++ b/xen/arch/arm/platforms/exynos5.c @@ -0,0 +1,86 @@ +/* + * 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 mappings for dom0 (Not in the DTS) */ +static int exynos5_specific_mapping(struct domain *d) +{ + /* 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 uint32_t exynos5_quirks(void) +{ + return PLATFORM_QUIRK_DOM0_MAPPING_11; +} + +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, + .quirks = exynos5_quirks, +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-May-08 02:33 UTC
[PATCH V2 32/33] xen/arm: WORKAROUND Support kick cpus 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. Theses modifications aim to be removed as soon as possible. It should be moved either in a platform specific boot-wrapper (which will be start before Xen), or in the bootloader (assuming U-Boot/Grub will support SMP). Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - Add WORKAROUND keyword in the title - Add fall-through comment when it''s needed - setup the spis with a while loop instead of a do-while loop --- xen/arch/arm/arm32/head.S | 19 +++++++- xen/arch/arm/arm32/mode_switch.S | 75 +++++++++++++++++++++++------- xen/include/asm-arm/platforms/vexpress.h | 11 +++++ 3 files changed, 86 insertions(+), 19 deletions(-) diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S index df71a31..0996a6d 100644 --- a/xen/arch/arm/arm32/head.S +++ b/xen/arch/arm/arm32/head.S @@ -76,7 +76,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 */ @@ -119,11 +119,25 @@ boot_cpu: bl putn PRINT(" booting -\r\n") #endif + /* Secondary CPUs doesn''t have machine ID + * - Store machine ID on boot CPU + * - Load machine ID on secondary CPUs + * Machine ID is needed in kick_cpus and enter_hyp_mode */ + 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 */ /* Wake up secondary cpus */ teq r12, #0 bleq kick_cpus + 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 */ @@ -403,6 +417,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..c92a1cf 100644 --- a/xen/arch/arm/arm32/mode_switch.S +++ b/xen/arch/arm/arm32/mode_switch.S @@ -20,14 +20,21 @@ #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 + /* otherwise versatile express */ /* write start paddr to v2m sysreg FLAGSSET register */ ldr r0, =(V2M_SYS_MMIO_BASE) /* base V2M sysreg MMIO address */ dsb @@ -38,8 +45,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 +70,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 +89,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 */ +1: teq r4, #0 + beq skip_spis + add r0, r0, #4 /* Go to the new group */ + str r2, [r0] /* Update the group */ + sub r4, r4, #1 + b 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-May-08 02:33 UTC
[PATCH V2 33/33] 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> Acked-by: Ian Campbell <ian.campbell@citrix.com> Changes in v2: - Remove stray gi"t diff" --- 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 6414c89..e3cfaf1 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. + */ #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
Gihun Jung
2013-May-08 07:03 UTC
Re: [PATCH V2 00/33] Support multiple ARM platforms in Xen
> If you want to try this patch series you can clone: > git clone -b arm-v2 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. > > Feel free to test this branch during Xen test day. The wiki has been updated > for the arndale board: > http://wiki.xen.org/wiki/Xen_ARM_with_Virtualization_Extensions/Arndale > > It''s now based on: > - this patch series for Xen > - linux 3.9 >Hello, While I am testing on your new patch series on the Arndale Board, I have found some mismatching items between wiki and source code. 1. dts path problem: from kernel 3.9 ( my guessing.. :) ), dtb file will be created in the same directory with dts file: arch/arm/boot/dts/*.dtb. However, in the wiki, it still describe dtb path is in arch/arm/boot/*.dtb. 2. early_printk uart: In the branch name "arndale" from your linux tree (git://xenbits.xen.org/people/julieng/linux-arm.git), exynos5250-arndale.dts describes "console=com1,dbgp com1=serial0" as a boot argument for early_printk. However, in your newer patch series for XenARM, ${xensrc}/drivers/char/arm-uart.c try to find console that has node name as "dtuart". So, I think it is required to modify "exynos5250-arndale.dts" file like: - console=com1,dbgp com1=serial0 +console=dtuart dtuart=serial0 Please consider this matters.> Feel free to test this branch during the Xen test day on both the versatile > express and the arndale board. > > Cheers,I am really enjoying to testing with your newly release patch series on the arndale board. But, I am still facing some problems :( I will post the problem to the mailing list later. Sincerely yours, Gihun Jung
Julien Grall
2013-May-08 11:01 UTC
Re: [PATCH V2 00/33] Support multiple ARM platforms in Xen
On 8 May 2013 08:03, Gihun Jung <gihun.jung@gmail.com> wrote:> > > If you want to try this patch series you can clone: > > git clone -b arm-v2 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. > > > > Feel free to test this branch during Xen test day. The wiki has been updated > > for the arndale board: > > http://wiki.xen.org/wiki/Xen_ARM_with_Virtualization_Extensions/Arndale > > > > It''s now based on: > > - this patch series for Xen > > - linux 3.9 > > > Hello, > > While I am testing on your new patch series on the Arndale Board, I > have found some mismatching items between wiki and source code.Hi, Thansk for testing the arndale board with Xen!> 1. dts path problem: > from kernel 3.9 ( my guessing.. :) ), dtb file will be created in the > same directory with dts file: arch/arm/boot/dts/*.dtb. > However, in the wiki, it still describe dtb path is in arch/arm/boot/*.dtb.The wiki page has been updated.> 2. early_printk uart: > In the branch name "arndale" from your linux tree > (git://xenbits.xen.org/people/julieng/linux-arm.git), > exynos5250-arndale.dts describes "console=com1,dbgp com1=serial0" as a > boot argument for early_printk. > However, in your newer patch series for XenARM, > ${xensrc}/drivers/char/arm-uart.c try to find console that has node > name as "dtuart". So, I think it is required to modify > "exynos5250-arndale.dts" file like: > - console=com1,dbgp com1=serial0 > +console=dtuart dtuart=serial0I have pushed a fix in the linux''s tree commit "08d452d". Cheers, -- Julien Grall
Ian Campbell
2013-May-08 13:00 UTC
Re: [PATCH V2 04/33] xen/arm: Bump early printk internal buffer to 512
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> When debug is enabled in device tree code, some lines > are bigger than 80 characters. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com> Although if we can also take steps to not let the line length get too long that would be valuable, I can see 80-100 being tolerable but if we are actually seeing lines with 512 characters that is an issue in its own right. I appreciate you''ve just picked a "big enough" number and we hopefully aren''t seeing anything like 512 in practice.> Changes in v2: > - Move buffer to a static variable > --- > xen/arch/arm/early_printk.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > > diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c > index bdf4c0e..0f99a43 100644 > --- a/xen/arch/arm/early_printk.c > +++ b/xen/arch/arm/early_printk.c > @@ -29,6 +29,9 @@ void __init early_putch(char c) > *r = c; > } > > +/* Early printk buffer */ > +static char __initdata buf[512]; > + > static void __init early_puts(const char *s) > { > while (*s != ''\0'') { > @@ -41,8 +44,6 @@ static void __init early_puts(const char *s) > > static void __init early_vprintk(const char *fmt, va_list args) > { > - char buf[80]; > - > vsnprintf(buf, sizeof(buf), fmt, args); > early_puts(buf); > }
Ian Campbell
2013-May-08 13:11 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> +/** > + * 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);The issue here is that there is code which wants to log which can be called either via dt_unflatten_host_device_tree or later on? There seems to be at least some calls to dt_dprintk which are only called via dt_unfla..., I think these can and should just use early_printk (or a macro to make them a debug thing). Likewise if there are functions which are only called later then they should just use printk direct (or a macro..) Which only leaves ones which are both? How many are these? I''m inclined towards suggesting that if they are debug prints which are disabled by default and require a recompile to enable then the person doing the debugging can select whether they care about early or late messages by #define-ing DEBUG or EARLY_DEBUG or both as required.> +/** > + * Host device tree > + * DO NOT modify it!Can it be const?> + */ > +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 >
Ian Campbell
2013-May-08 13:18 UTC
Re: [PATCH V2 08/33] xen/arm: Add helpers to use the device tree
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Changes in v2: > - use dt_node_cmp and dt_compat_cmp in early device tree code > --- > xen/common/device_tree.c | 127 ++++++++++++++++++++++++++++++++++++++++- > xen/include/xen/device_tree.h | 120 ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 245 insertions(+), 2 deletions(-) > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > index bdf8871..449c332 100644 > --- a/xen/common/device_tree.c > +++ b/xen/common/device_tree.c > @@ -88,20 +88,23 @@ bool_t device_tree_type_matches(const void *fdt, int node, const char *match) > if ( prop == NULL ) > return 0; > > - return !strcmp(prop, match); > + return !dt_node_cmp(prop, match); > } > > bool_t device_tree_node_compatible(const void *fdt, int node, const char *match)Aside: I wonder if any of these should be __init...> { > int len, l; > + int mlen; > const void *prop; > > + mlen = strlen(match); > + > prop = fdt_getprop(fdt, node, "compatible", &len); > if ( prop == NULL ) > return 0; > > while ( len > 0 ) { > - if ( !strcmp(prop, match) ) > + if ( !dt_compat_cmp(prop, match, mlen) )Is there a change in behaviour here where strlen(match) < strlen(prop)? I may be mistaken but I think match=="foo" would be compatible with a node "foobar" now whereas it wasn''t before. On the otherhand this is the same behaviour as dt_device_is_compatible so maybe it is expected. I seem to recall some name matching code which explicitly wanted to handle foo@0 as matching foo and things, not sure that applies here though.> return 1; > l = strlen(prop) + 1; > prop += l; > @@ -573,6 +576,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;
Ian Campbell
2013-May-08 13:23 UTC
Re: [PATCH V2 09/33] xen/arm: Add helpers to retrieve an address from the device tree
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> 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 449c332..8d37018 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);Spacing is weird here. Hard tabs perhaps?> +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; > + }Indentation.> + 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; > + }Indentation.> + 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);Ide...> + > + /* 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);Inde...> diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h > index 879b75d..ce34ba5 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 resolveaddress> + * @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 deviceaddresses> + * @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/occurred Apart from the indentation and the spelling errors I''m inclined to trust that the actual logic is ok. So if you fix the above (and any indentation I missed): Acked-by: Ian Campbell <ian.campbell@citrix.com>> + */ > +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 >
Ian Campbell
2013-May-08 13:30 UTC
Re: [PATCH V2 10/33] xen/arm: Add helpers to retrieve an interrupt description from the device tree
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Changes in v2: > - Move interrupt type from xen/irq.h to xen/device_tree.h > - Prefix all defines by DT_ > --- > xen/common/device_tree.c | 362 +++++++++++++++++++++++++++++++++++++++++ > xen/include/xen/device_tree.h | 130 +++++++++++++++ > 2 files changed, 492 insertions(+) > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > index 8d37018..e5ff779 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 > @@ -1020,6 +1023,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; > @@ -1051,6 +1129,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 interruptssynthesized> +/** > + * 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 interruptspecifying> * DO NOT modify it! > */ > extern struct dt_device_node *dt_host; > > +/** > + * Primary interrupt controller > + * Exynos SOC has an interrupt combiner, interrupt has no physical^an> + * 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".... parent which is ...> +/** > * dt_number_of_address - Get the number of addresse for a deviceaddresses> * @device: the device whose number of address is to be retrieved > * > @@ -300,6 +399,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 irqtranslate Like with the previous patch I''m inclined to trust the logic is correct. So if you fix the typoes: Acked-by: Ian Campbell <ian.campbell@citrix.com> Ian.
Ian Campbell
2013-May-08 13:31 UTC
Re: [PATCH V2 11/33] xen/arm: Introduce gic_route_dt_irq
On Wed, 2013-05-08 at 03:33 +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> > > Changes in v2: > - Use dt_irq_is_level_trigger instead of the old name irq_is_level_triggerShould be ...is_level_triggered(). Other than that: Acked-by: Ian Campbell <ian.campbell@citrix.com> Ian.
On Wed, 2013-05-08 at 03:33 +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>Acked-by: Ian Campbell <ian.campbell@citrix.com>
Julien Grall
2013-May-08 13:34 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On 05/08/2013 02:11 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: > >> +/** >> + * 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); > > The issue here is that there is code which wants to log which can be > called either via dt_unflatten_host_device_tree or later on?Right.> There seems to be at least some calls to dt_dprintk which are only > called via dt_unfla..., I think these can and should just use > early_printk (or a macro to make them a debug thing). Likewise if there > are functions which are only called later then they should just use > printk direct (or a macro..)There are lots of dt_dprintk in functions to retrieve an IRQ and an address.> Which only leaves ones which are both? How many are these? I''m inclined > towards suggesting that if they are debug prints which are disabled by > default and require a recompile to enable then the person doing the > debugging can select whether they care about early or late messages by > #define-ing DEBUG or EARLY_DEBUG or both as required.We can''t choose at compile time. Early printk function is in init code section. So at the end of boot the function will disappear. Device tree function could be called after the end of the boot. For the moment it''s not the case. The best solution would be: early_printk is directly handled in console as linux does.>> +/** >> + * Host device tree >> + * DO NOT modify it! > > Can it be const?No :/. I choose to runtime information in the device tree. It''s usefull to know if a device is used by Xen or someone else. I have just notice that dt_host is only used in domain_build.c to browse all the nodes. I can either provide a helper which return the host DT or add a function to call a function and recurse on each node. -- Julien Grall
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> This function will replace setup_irq in later patch. It takes a dt_irq > as first argument instead of an unsigned int. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>
Ian Campbell
2013-May-08 13:41 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On Wed, 2013-05-08 at 14:34 +0100, Julien Grall wrote:> > Which only leaves ones which are both? How many are these? I''m inclined > > towards suggesting that if they are debug prints which are disabled by > > default and require a recompile to enable then the person doing the > > debugging can select whether they care about early or late messages by > > #define-ing DEBUG or EARLY_DEBUG or both as required. > > We can''t choose at compile time. Early printk function is in init code > section. So at the end of boot the function will disappear.Oh, right. Perhaps something could be conditional on system_state SYS_STATE_active, this happens not long before we discard the initial sections.> Device tree function could be called after the end of the boot. For the > moment it''s not the case. > > The best solution would be: early_printk is directly handled in console > as linux does.That does sound best.> >> +/** > >> + * Host device tree > >> + * DO NOT modify it! > > > > Can it be const? > > No :/. I choose to runtime information in the device tree. It''s usefull > to know if a device is used by Xen or someone else. > > I have just notice that dt_host is only used in domain_build.c to browse > all the nodes. I can either provide a helper which return the host DT or > add a function to call a function and recurse on each node.I think it is OK, I was only wondering if it could be const. Ian.
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> This function will replace request_irq in a later patch. It takes a dt_irq > as first argument instead of an unsigned int. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>
Ian Campbell
2013-May-08 13:46 UTC
Re: [PATCH V2 15/33] xen/arm: Use hierarchical device tree to retrieve GIC information
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> - Remove early parsing for GIC addresses > - Remove hard coded maintenance IRQ number > > Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Changes in v2: > - use the new function request_dt_irq > --- > 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 1efa9a3..34304b3 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; /* Number of interrupts (SPIs + PPIs + SGIs) */ > + 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");Please can we keep this last check separate and after the print, this way we get to see why it failed (not present vs invalid). I''m ambivalent about keeping the !gic.Xbase separate or including it in the res check. Ian.
Ian Campbell
2013-May-08 13:50 UTC
Re: [PATCH V2 16/33] xen/arm: Retrieve timer interrupts from the device tree
> @@ -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);It occurs to me that this guy (and the underlying function) should probably take a cpumask_t. Not now though.> +} > + > /* 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_dt_irq(&timer_irq[HYP_PPI], timer_interrupt, 0, "hyptimer", NULL); > + request_dt_irq(&timer_irq[VIRT_PPI], vtimer_interrupt, 0, > + "virtimer", NULL); > + request_dt_irq(&timer_irq[PHYS_NONSECURE_PPI], timer_interrupt, 2, > + "phytimer", NULL);Why the change to flags == 2 here? Ian.
Ian Campbell
2013-May-08 13:52 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: ...> - Use DOMID_XEN instead of DOMID_INVALID for DT_USED_BY_XEN > [...]> +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 */It occurred to me as I reviewed the rest of the series that since this actually a DOMID there is no reason not to use DOMID_XEN directly and remove DT_USED_BY_XEN. Ian.
Ian Campbell
2013-May-08 13:52 UTC
Re: [PATCH V2 18/33] xen/arm: Introduce a generic way to use a device from the device tree
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>
Ian Campbell
2013-May-08 14:01 UTC
Re: [PATCH V2 20/33] xen/arm: Add generic UART to get the device in the device tree
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> This generic UART will find the right UART via xen command line > with dtuart=myserial.I suppose there way to determine sensible default, since it differs on every platform?> "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>You need to CC code code maintainers when you change core code. Keir added.> > Changes in v2: > - Use dtuart parameter instead of com1. The first one is more arm > while the latter is more x86 > --- > xen/arch/arm/setup.c | 3 +- > xen/drivers/char/Makefile | 1 + > xen/drivers/char/arm-uart.c | 81 ++++++++++++++++++++++++++++++++++++++++++ > xen/drivers/char/serial.c | 6 ++++ > xen/include/asm-arm/config.h | 2 +- > xen/include/xen/serial.h | 7 ++++ > 6 files changed, 98 insertions(+), 2 deletions(-) > create mode 100644 xen/drivers/char/arm-uart.c > > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index e4228f7..7b2df8b 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -435,8 +435,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..c76875e > --- /dev/null > +++ b/xen/drivers/char/arm-uart.c > @@ -0,0 +1,81 @@ > +/* > + * 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 UART port with a string: > + * alias > + * > + * @alias: alias used in the device tree for the UART > + * TODO: Implement config in each UART driver. > + */ > +static char __initdata opt_dtuart[30] = ""; > +string_param("dtuart", opt_dtuart); > + > +void __init arm_uart_init(void)This (and the file and struct serial_arm_defaults etc) could perhaps be better called dt_uart_init etc? There''s nothing inherently ARM specific here.> +{ > + struct dt_device_node *dev; > + int ret; > + u64 addr, size; > + struct serial_arm_defaults defaults; > + const char *devalias = opt_dtuart; > + > + if ( !console_has("dtuart") || !strcmp(opt_dtuart, "") ) > + { > + early_printk("No console\n"); > + return; > + } > + > + early_printk("Looking for UART console %s\n", devalias); > + dev = dt_find_node_by_alias(devalias); > + > + if ( !dev ) > + { > + early_printk("Unable to find device \"%s\"\n", devalias); > + return; > + } > + > + /* TODO: Handle UART with 0 or multiple base address */ > + 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/drivers/char/serial.c b/xen/drivers/char/serial.c > index 0ae7e4d..c4c4a84 100644 > --- a/xen/drivers/char/serial.c > +++ b/xen/drivers/char/serial.c > @@ -271,6 +271,12 @@ int __init serial_parse_handle(char *conf) > goto common; > } > > + if ( !strncmp(conf, "dtuart", 5) ) > + { > + handle = SERHND_COM1;Do you mean COM1 here? Or did you intend to add SERHND_DT?> + goto common; > + } > + > if ( strncmp(conf, "com", 3) ) > goto fail; > > diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h > index 98a3a43..8ed72f5 100644 > --- a/xen/include/asm-arm/config.h > +++ b/xen/include/asm-arm/config.h > @@ -39,7 +39,7 @@ > > #define CONFIG_VIDEO 1 > > -#define OPT_CONSOLE_STR "com1" > +#define OPT_CONSOLE_STR "dtuart" > > #ifdef MAX_PHYS_CPUS > #define NR_CPUS MAX_PHYS_CPUS > diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h > index 5de5171..f548f8b 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,12 @@ 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
2013-May-08 15:15 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On 05/08/2013 02:41 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 14:34 +0100, Julien Grall wrote: >>> Which only leaves ones which are both? How many are these? I''m inclined >>> towards suggesting that if they are debug prints which are disabled by >>> default and require a recompile to enable then the person doing the >>> debugging can select whether they care about early or late messages by >>> #define-ing DEBUG or EARLY_DEBUG or both as required. >> >> We can''t choose at compile time. Early printk function is in init code >> section. So at the end of boot the function will disappear. > > Oh, right. > > Perhaps something could be conditional on system_state > SYS_STATE_active, this happens not long before we discard the initial > sections.I think it''s too late. If we use early_printk until this stage, we will lose some usefull debug when early printk is disabled (ie most of the time). How about adding the missing system_state = SYS_STATE_boot just after console_init_preirq? Early printk will only be used when system_state =SYS_STATE_early_boot.>> Device tree function could be called after the end of the boot. For the >> moment it''s not the case. >> >> The best solution would be: early_printk is directly handled in console >> as linux does. > > That does sound best.I will send a patch later for this. -- Julien
Ian Campbell
2013-May-08 15:17 UTC
Re: [PATCH V2 21/33] xen/arm: Use device tree API in pl011 UART driver
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> @@ -227,32 +239,56 @@ 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) > +/* TODO: Parse UART config from the command line */ > +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;Should this not come from struct dt_device_node? Perhaps the driver needs to be instantiating its own FIXMAP mapping instead of doing it in common code? In fact can we not get rid of the fixmap for the runtime (not early) console and use the ioremap stuff which Stefano just enabled with his vmap patches, or the early_ioremap stuff if necessary. That does then call into question the whole serial_arm_defaults thing. Perhaps index should just be the order in which they are registered (and at the moment it is effectively hardcoded to 0 anyway)> + > + 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; > }Ian.
Julien Grall
2013-May-08 15:22 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On 05/08/2013 02:52 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: > ... >> - Use DOMID_XEN instead of DOMID_INVALID for DT_USED_BY_XEN >> [...] > >> +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 */ > > It occurred to me as I reviewed the rest of the series that since this > actually a DOMID there is no reason not to use DOMID_XEN directly and > remove DT_USED_BY_XEN.Will be fix on the next patch series. -- Julien
Ian Campbell
2013-May-08 15:28 UTC
Re: [PATCH V2 22/33] xen/arm: Use the device tree to map the address range and IRQ to dom0
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> - 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> > > Changes in v2: > - Use the new function dt_irq_is_level_trigger > - Disable DEBUG_DT by default > - Rename parse_device_tree to map_device_from_device_treeShould be map_devices_...> + /**Javadoc!> + * 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",you might mean "skipped its controller" ? But I think a clearer message would be "irq %u not connected to primary controller" or something.> + 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);The # format specifier is required by $STANDARD to not be all that sensible and/or consistent when when the value is 0, i.e. printf("%#x\n", 0) => "0" printf("%#x\n", 1) => "0x1" Worse if you use widths then: printf("%#02x\n", 0); => "00" printf("%#02x\n", 1); => "0x1" printf("%#04x\n", 0); => "0000" printf("%#04x\n", 1); => "0x01" For this reason we tend to avoid # and just use "0x%...", assuming irq==0 is a possibility, and likewise below addr==0 it''s probably better to avoid #.> + /* Don''t check return because the IRQ can be use by multiple device */"used by"> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c > index f7b9889..ddad0c8 100644 > --- a/xen/arch/arm/gic.c > +++ b/xen/arch/arm/gic.c > @@ -692,13 +692,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) > @@ -706,6 +707,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); > @@ -713,9 +715,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 = dt_irq_is_level_trigger(irq); > + > + gic_set_irq_properties(irq->irq, level, 1u << smp_processor_id(), 0xa0);By the end of this series are all callers going through the above dance? git_set_irq_properties could take a dt_irq? Ian.
Julien Grall
2013-May-08 15:31 UTC
Re: [PATCH V2 08/33] xen/arm: Add helpers to use the device tree
On 05/08/2013 02:18 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> >> Changes in v2: >> - use dt_node_cmp and dt_compat_cmp in early device tree code >> --- >> xen/common/device_tree.c | 127 ++++++++++++++++++++++++++++++++++++++++- >> xen/include/xen/device_tree.h | 120 ++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 245 insertions(+), 2 deletions(-) >> >> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c >> index bdf8871..449c332 100644 >> --- a/xen/common/device_tree.c >> +++ b/xen/common/device_tree.c >> @@ -88,20 +88,23 @@ bool_t device_tree_type_matches(const void *fdt, int node, const char *match) >> if ( prop == NULL ) >> return 0; >> >> - return !strcmp(prop, match); >> + return !dt_node_cmp(prop, match); >> } >> >> bool_t device_tree_node_compatible(const void *fdt, int node, const char *match) > > Aside: I wonder if any of these should be __init...I think yes.> >> { >> int len, l; >> + int mlen; >> const void *prop; >> >> + mlen = strlen(match); >> + >> prop = fdt_getprop(fdt, node, "compatible", &len); >> if ( prop == NULL ) >> return 0; >> >> while ( len > 0 ) { >> - if ( !strcmp(prop, match) ) >> + if ( !dt_compat_cmp(prop, match, mlen) ) > > Is there a change in behaviour here where strlen(match) < strlen(prop)? > > I may be mistaken but I think match=="foo" would be compatible with a > node "foobar" now whereas it wasn''t before.I have checked the linux code and the also use strncmp with the length of "match"/"compatible".> On the otherhand this is the same behaviour as dt_device_is_compatible > so maybe it is expected. I seem to recall some name matching code which > explicitly wanted to handle foo@0 as matching foo and things, not sure > that applies here though.This behaviour only happens for the compatible node. -- Julien Grall
Julien Grall
2013-May-08 15:32 UTC
Re: [PATCH V2 09/33] xen/arm: Add helpers to retrieve an address from the device tree
On 05/08/2013 02:23 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> 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 449c332..8d37018 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); > > Spacing is weird here. Hard tabs perhaps?Right. I will fix all the errors on the next patch series. -- Julien
Ian Campbell
2013-May-08 15:32 UTC
Re: [PATCH V2 23/33] xen/arm: Allow Xen to run on multiple platform without recompilation
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c > index bfc41c2..1114fe7 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;Might be better to read this after platform_init_time, in case p_i_t does something "magic" on this platform?> +/* 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);I don''t think the fixmap is per-PCPU so you probably want some locking here. FIXMAP_MISC is a bit of an awful thing, but this isn''t especially new, so OK.> + > + 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); > +} > +Ian.
Ian Campbell
2013-May-08 15:34 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On Wed, 2013-05-08 at 16:15 +0100, Julien Grall wrote:> On 05/08/2013 02:41 PM, Ian Campbell wrote: > > > On Wed, 2013-05-08 at 14:34 +0100, Julien Grall wrote: > >>> Which only leaves ones which are both? How many are these? I''m inclined > >>> towards suggesting that if they are debug prints which are disabled by > >>> default and require a recompile to enable then the person doing the > >>> debugging can select whether they care about early or late messages by > >>> #define-ing DEBUG or EARLY_DEBUG or both as required. > >> > >> We can''t choose at compile time. Early printk function is in init code > >> section. So at the end of boot the function will disappear. > > > > Oh, right. > > > > Perhaps something could be conditional on system_state > > SYS_STATE_active, this happens not long before we discard the initial > > sections. > > > I think it''s too late. If we use early_printk until this stage, we will > lose some usefull debug when early printk is disabled (ie most of the time). > > How about adding the missing system_state = SYS_STATE_boot just after > console_init_preirq? Early printk will only be used when system_state => SYS_STATE_early_boot.I think this is a common thing so it''d need wider discussion.> >> Device tree function could be called after the end of the boot. For the > >> moment it''s not the case. > >> > >> The best solution would be: early_printk is directly handled in console > >> as linux does. > > > > That does sound best. > > > I will send a patch later for this.Does that make the above moot? Ian.
Ian Campbell
2013-May-08 15:35 UTC
Re: [PATCH V2 23/33] xen/arm: Allow Xen to run on multiple platform without recompilation
On Wed, 2013-05-08 at 16:32 +0100, Ian Campbell wrote:> > +/* 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); > > I don''t think the fixmap is per-PCPU so you probably want some locking > here. > > FIXMAP_MISC is a bit of an awful thing, but this isn''t especially new, > so OK.In fact now I''m wondering if the platform specific code shouldn''t establish its own permanent mapping with ioremap and use that. Ian.
Julien Grall
2013-May-08 15:49 UTC
Re: [PATCH V2 15/33] xen/arm: Use hierarchical device tree to retrieve GIC information
On 05/08/2013 02:46 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> - Remove early parsing for GIC addresses >> - Remove hard coded maintenance IRQ number >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> >> Changes in v2: >> - use the new function request_dt_irq >> --- >> 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 1efa9a3..34304b3 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; /* Number of interrupts (SPIs + PPIs + SGIs) */ >> + 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"); > > Please can we keep this last check separate and after the print, this > way we get to see why it failed (not present vs invalid).I will fix it on the next patch series.> > I''m ambivalent about keeping the !gic.Xbase separate or including it in > the res check.I don''t see a good reason why the gic base address could not be 0. I prefer to remove this check. -- Julien
Julien Grall
2013-May-08 15:53 UTC
Re: [PATCH V2 16/33] xen/arm: Retrieve timer interrupts from the device tree
On 05/08/2013 02:50 PM, Ian Campbell wrote:>> @@ -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); > > It occurs to me that this guy (and the underlying function) should > probably take a cpumask_t. Not now though. > >> +} >> + >> /* 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_dt_irq(&timer_irq[HYP_PPI], timer_interrupt, 0, "hyptimer", NULL); >> + request_dt_irq(&timer_irq[VIRT_PPI], vtimer_interrupt, 0, >> + "virtimer", NULL); >> + request_dt_irq(&timer_irq[PHYS_NONSECURE_PPI], timer_interrupt, 2, >> + "phytimer", NULL); > > Why the change to flags == 2 here?It''s a mistake. I will fix it on the next patch series. -- Julien
Ian Campbell
2013-May-08 15:54 UTC
Re: [PATCH V2 24/33] xen/arm: WORKAROUND 1:1 memory mapping for dom0
On Wed, 2013-05-08 at 03:33 +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. > > 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>(Somewhat reluctantly) Acked-by: Ian Campbell <ian.campbell@citrix.com> I consider this to be a temporary workaround and at some point (possibly even as soon as 4.4) I intend to push for its removal, even if this breaks some platforms which have not by then implemented SYS MMU support for whatever reason. Vendors who care about support for their platform under Xen need to sort out SYS MMU support for them sooner rather than later (which probably means patches, but documentation would be at least a tolerable alternative).> + * Usefull on platform where System MMU is not yet implemented"Useful" Ian.
Ian Campbell
2013-May-08 15:56 UTC
Re: [PATCH V2 15/33] xen/arm: Use hierarchical device tree to retrieve GIC information
On Wed, 2013-05-08 at 16:49 +0100, Julien Grall wrote:> On 05/08/2013 02:46 PM, Ian Campbell wrote:> > Please can we keep this last check separate and after the print, this > > way we get to see why it failed (not present vs invalid). > > > I will fix it on the next patch series.Thanks.> > > > I''m ambivalent about keeping the !gic.Xbase separate or including it in > > the res check. > > > I don''t see a good reason why the gic base address could not be 0. I > prefer to remove this check.True, agreed. Ian.
Julien Grall
2013-May-08 15:58 UTC
Re: [PATCH V2 20/33] xen/arm: Add generic UART to get the device in the device tree
On 05/08/2013 03:01 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> This generic UART will find the right UART via xen command line >> with dtuart=myserial. > > I suppose there way to determine sensible default, since it differs on > every platform? > >> "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> > > You need to CC code code maintainers when you change core code. Keir > added. >> >> Changes in v2: >> - Use dtuart parameter instead of com1. The first one is more arm >> while the latter is more x86 >> --- >> xen/arch/arm/setup.c | 3 +- >> xen/drivers/char/Makefile | 1 + >> xen/drivers/char/arm-uart.c | 81 ++++++++++++++++++++++++++++++++++++++++++ >> xen/drivers/char/serial.c | 6 ++++ >> xen/include/asm-arm/config.h | 2 +- >> xen/include/xen/serial.h | 7 ++++ >> 6 files changed, 98 insertions(+), 2 deletions(-) >> create mode 100644 xen/drivers/char/arm-uart.c >> >> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c >> index e4228f7..7b2df8b 100644 >> --- a/xen/arch/arm/setup.c >> +++ b/xen/arch/arm/setup.c >> @@ -435,8 +435,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..c76875e >> --- /dev/null >> +++ b/xen/drivers/char/arm-uart.c >> @@ -0,0 +1,81 @@ >> +/* >> + * 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 UART port with a string: >> + * alias >> + * >> + * @alias: alias used in the device tree for the UART >> + * TODO: Implement config in each UART driver. >> + */ >> +static char __initdata opt_dtuart[30] = ""; >> +string_param("dtuart", opt_dtuart); >> + >> +void __init arm_uart_init(void) > > This (and the file and struct serial_arm_defaults etc) could perhaps be > better called dt_uart_init etc? There''s nothing inherently ARM specific > here.The FIXMAP_CONSOLE is ARM specific it can not works on x86. I''m wondering if it''s usefull to move FIXMAP_CONSOLE on each UART driver.>> +{ >> + struct dt_device_node *dev; >> + int ret; >> + u64 addr, size; >> + struct serial_arm_defaults defaults; >> + const char *devalias = opt_dtuart; >> + >> + if ( !console_has("dtuart") || !strcmp(opt_dtuart, "") ) >> + { >> + early_printk("No console\n"); >> + return; >> + } >> + >> + early_printk("Looking for UART console %s\n", devalias); >> + dev = dt_find_node_by_alias(devalias); >> + >> + if ( !dev ) >> + { >> + early_printk("Unable to find device \"%s\"\n", devalias); >> + return; >> + } >> + >> + /* TODO: Handle UART with 0 or multiple base address */ >> + 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/drivers/char/serial.c b/xen/drivers/char/serial.c >> index 0ae7e4d..c4c4a84 100644 >> --- a/xen/drivers/char/serial.c >> +++ b/xen/drivers/char/serial.c >> @@ -271,6 +271,12 @@ int __init serial_parse_handle(char *conf) >> goto common; >> } >> >> + if ( !strncmp(conf, "dtuart", 5) ) >> + { >> + handle = SERHND_COM1; > > Do you mean COM1 here? Or did you intend to add SERHND_DT?I mean COM1, I use the first serial slot for dtuart. I don''t really see why we need to extend the number of serial slot. -- Julien
Julien Grall
2013-May-08 16:23 UTC
Re: [PATCH V2 21/33] xen/arm: Use device tree API in pl011 UART driver
On 05/08/2013 04:17 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> @@ -227,32 +239,56 @@ 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) >> +/* TODO: Parse UART config from the command line */ >> +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; > > Should this not come from struct dt_device_node? > > Perhaps the driver needs to be instantiating its own FIXMAP mapping > instead of doing it in common code? In fact can we not get rid of the > fixmap for the runtime (not early) console and use the ioremap stuff > which Stefano just enabled with his vmap patches, or the early_ioremap > stuff if necessary.Right. I will use ioremap in the next patch series.> That does then call into question the whole serial_arm_defaults thing. > Perhaps index should just be the order in which they are registered (and > at the moment it is effectively hardcoded to 0 anyway)I''m thinking about using serial_arm_defaults for baud rate,... For the moment the different values are hardcoded. {arm,dt}_init_uart will parse the dtuart parameters on the command line and then fill serial_arm_defaults. -- Julien
Julien Grall
2013-May-08 16:32 UTC
Re: [PATCH V2 23/33] xen/arm: Allow Xen to run on multiple platform without recompilation
On 05/08/2013 04:35 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 16:32 +0100, Ian Campbell wrote: >>> +/* 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); >> >> I don''t think the fixmap is per-PCPU so you probably want some locking >> here. >> >> FIXMAP_MISC is a bit of an awful thing, but this isn''t especially new, >> so OK. > > In fact now I''m wondering if the platform specific code shouldn''t > establish its own permanent mapping with ioremap and use that.I will rework this patch with ioremap -- Julien
Julien Grall
2013-May-08 16:38 UTC
Re: [PATCH V2 23/33] xen/arm: Allow Xen to run on multiple platform without recompilation
On 05/08/2013 04:32 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c >> index bfc41c2..1114fe7 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; > > Might be better to read this after platform_init_time, in case p_i_t > does something "magic" on this platform?Ok. I will move the platform_init_time just before. -- Julien
Ian Campbell
2013-May-08 16:41 UTC
Re: [PATCH V2 20/33] xen/arm: Add generic UART to get the device in the device tree
On Wed, 2013-05-08 at 16:58 +0100, Julien Grall wrote:> On 05/08/2013 03:01 PM, Ian Campbell wrote: > > > On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: > >> This generic UART will find the right UART via xen command line > >> with dtuart=myserial. > > > > I suppose there way to determine sensible default, since it differs on > > every platform? > > > >> "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> > > > > You need to CC code code maintainers when you change core code. Keir > > added. > >> > >> Changes in v2: > >> - Use dtuart parameter instead of com1. The first one is more arm > >> while the latter is more x86 > >> --- > >> xen/arch/arm/setup.c | 3 +- > >> xen/drivers/char/Makefile | 1 + > >> xen/drivers/char/arm-uart.c | 81 ++++++++++++++++++++++++++++++++++++++++++ > >> xen/drivers/char/serial.c | 6 ++++ > >> xen/include/asm-arm/config.h | 2 +- > >> xen/include/xen/serial.h | 7 ++++ > >> 6 files changed, 98 insertions(+), 2 deletions(-) > >> create mode 100644 xen/drivers/char/arm-uart.c > >> > >> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > >> index e4228f7..7b2df8b 100644 > >> --- a/xen/arch/arm/setup.c > >> +++ b/xen/arch/arm/setup.c > >> @@ -435,8 +435,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..c76875e > >> --- /dev/null > >> +++ b/xen/drivers/char/arm-uart.c > >> @@ -0,0 +1,81 @@ > >> +/* > >> + * 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 UART port with a string: > >> + * alias > >> + * > >> + * @alias: alias used in the device tree for the UART > >> + * TODO: Implement config in each UART driver. > >> + */ > >> +static char __initdata opt_dtuart[30] = ""; > >> +string_param("dtuart", opt_dtuart); > >> + > >> +void __init arm_uart_init(void) > > > > This (and the file and struct serial_arm_defaults etc) could perhaps be > > better called dt_uart_init etc? There''s nothing inherently ARM specific > > here. > > The FIXMAP_CONSOLE is ARM specific it can not works on x86. I''m > wondering if it''s usefull to move FIXMAP_CONSOLE on each UART driver.I think I came to the same conclusion later in the series too, or more likely the uart drivers should use ioremap.> >> + if ( !strncmp(conf, "dtuart", 5) ) > >> + { > >> + handle = SERHND_COM1; > > > > Do you mean COM1 here? Or did you intend to add SERHND_DT? > > I mean COM1, I use the first serial slot for dtuart. I don''t really see > why we need to extend the number of serial slot.I just dislike using things with one name for another purpose. Ultimately this bit is up to Keir though. Ian.
Ian Campbell
2013-May-08 16:43 UTC
Re: [PATCH V2 21/33] xen/arm: Use device tree API in pl011 UART driver
On Wed, 2013-05-08 at 17:23 +0100, Julien Grall wrote:> > That does then call into question the whole serial_arm_defaults thing. > > Perhaps index should just be the order in which they are registered (and > > at the moment it is effectively hardcoded to 0 anyway) > > > I''m thinking about using serial_arm_defaults for baud rate,... For the > moment the different values are hardcoded. > > {arm,dt}_init_uart will parse the dtuart parameters on the command line > and then fill serial_arm_defaults.Perhaps instead of &serial_arm_defaults you should pass a char * pointer to opt_dtuart? This would allow for per-device settings and is consistent with the ns16550 driver. Ian.
Julien Grall
2013-May-08 16:55 UTC
Re: [PATCH V2 21/33] xen/arm: Use device tree API in pl011 UART driver
On 05/08/2013 05:43 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 17:23 +0100, Julien Grall wrote: >>> That does then call into question the whole serial_arm_defaults thing. >>> Perhaps index should just be the order in which they are registered (and >>> at the moment it is effectively hardcoded to 0 anyway) >> >> >> I''m thinking about using serial_arm_defaults for baud rate,... For the >> moment the different values are hardcoded. >> >> {arm,dt}_init_uart will parse the dtuart parameters on the command line >> and then fill serial_arm_defaults. > > Perhaps instead of &serial_arm_defaults you should pass a char * pointer > to opt_dtuart? This would allow for per-device settings and is > consistent with the ns16550 driver.Ok. I will modify it in the next patch series. -- Julien
Julien Grall
2013-May-08 16:59 UTC
Re: [PATCH V2 22/33] xen/arm: Use the device tree to map the address range and IRQ to dom0
On 05/08/2013 04:28 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> - 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> >> >> Changes in v2: >> - Use the new function dt_irq_is_level_trigger >> - Disable DEBUG_DT by default >> - Rename parse_device_tree to map_device_from_device_tree > > Should be map_devices_...Will be fix on the next patch series.>> + /** > > Javadoc! > >> + * 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", > > you might mean "skipped its controller" ? But I think a clearer message > would be "irq %u not connected to primary controller" or something. > >> + 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); > > The # format specifier is required by $STANDARD to not be all that > sensible and/or consistent when when the value is 0, i.e. > printf("%#x\n", 0) => "0" > printf("%#x\n", 1) => "0x1" > Worse if you use widths then: > printf("%#02x\n", 0); => "00" > printf("%#02x\n", 1); => "0x1" > printf("%#04x\n", 0); => "0000" > printf("%#04x\n", 1); => "0x01" > > For this reason we tend to avoid # and just use "0x%...", assuming > irq==0 is a possibility, and likewise below addr==0 it''s probably better > to avoid #.Thanks for this hint. I will replace all my %#x by 0x%x.>> + /* Don''t check return because the IRQ can be use by multiple device */ > > "used by" > >> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c >> index f7b9889..ddad0c8 100644 >> --- a/xen/arch/arm/gic.c >> +++ b/xen/arch/arm/gic.c >> @@ -692,13 +692,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) >> @@ -706,6 +707,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); >> @@ -713,9 +715,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 = dt_irq_is_level_trigger(irq); >> + >> + gic_set_irq_properties(irq->irq, level, 1u << smp_processor_id(), 0xa0); > > By the end of this series are all callers going through the above dance? > git_set_irq_properties could take a dt_irq?No. I can add patch to use a dt_irq. -- Julien
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> All calls to this function in ARM code have been removed. This function SHOULD > not be used. If someone calls this function, a linking error will occur. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> All calls to this function in ARM code have been removed. This function SHOULD > not be used. If someone calls this function, a linking error will occur. > > Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>
Ian Campbell
2013-May-09 10:10 UTC
Re: [PATCH V2 28/33] xen/arm: Don''t use pl011 UART by default for early printk
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> 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.oIs this correct now that you are using debug-pl011.inc?> /* Print a 32-bit number in hex. Specific to the PL011 UART. > * r0: Number to print. > - * clobbers r0-r3 */ > + * r11: Early UART base address > + * clobbers r1-r3 */This still clobbers r0, via the lsl below.> putn: > 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: > + early_uart_ready r11, r2 > 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) */ > + early_uart_transmit r11, r2 > lsl r0, #4 /* Roll it through one nybble at a time */ > subs r3, r3, #1 > bne 1b > @@ -329,51 +329,44 @@ 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. > + * x23: Early UART base address > + * Clobbers x0-x1 */Does it actually clobber x1?> 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) */ > + early_uart_init x23, 0 > adr x0, 1f > - b puts > + b puts /* Jump to puts */ > 1: .asciz "- UART enabled -\r\n" > .align 4
Ian Campbell
2013-May-09 10:13 UTC
Re: [PATCH V2 29/33] xen/arm: Add exynos 4210 UART support
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> + /* TODO: should be updated */ > + /* Baud rate already set: read it out from the divisor latch. */ > +#if 0 > + divisor = (uart->regs[IBRD] << 6) | uart->regs[FBRD]; > + uart->baud = (uart->clock_hz << 2) / divisor; > +#endifCan we drop the #if 0, extending the comment if necessary, or if possible drop the whole thing.> +static int __init exynos4210_uart_init(struct dt_device_node *dev, > + const void *data) > +{ > + const struct serial_arm_defaults *defaults = data; > + struct exynos4210_uart *uart; > + int res; > + > + if ( (defaults->index < 0) || (defaults->index > 1) ) > + return -EINVAL; > + > + uart = &exynos4210_com[defaults->index]; > + > + /* uart->clock_hz = 0x16e3600; */ > + uart->baud = BAUD_AUTO;//115200;Drop the //115200.> diff --git a/xen/include/asm-arm/exynos4210-uart.h b/xen/include/asm-arm/exynos4210-uart.h > new file mode 100644 > index 0000000..1527521 > --- /dev/null > +++ b/xen/include/asm-arm/exynos4210-uart.h > @@ -0,0 +1,111 @@ > +/* > + * xen/include/asm-arm/exynos4210-uart.h > + * > + * Common constant definition between ealry printk and the UART driver"early" If you fix all the above then Acked-by: Ian Campbell <ian.campbell@citrix.com> Ian.
Ian Campbell
2013-May-09 10:16 UTC
Re: [PATCH V2 30/33] xen/arm: Add Exynos 4210 UART support for early printk
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> From: Anthony PERARD <anthony.perard@citrix.com> > > Signed-off-by: Anthony PERARD <anthony.perard@citrix.com> > Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Changes in v2: > - Use assembly macro instead of function > - Add Anthony as first author > --- > docs/misc/arm/early-printk.txt | 1 + > xen/arch/arm/Rules.mk | 4 ++ > xen/arch/arm/arm32/Makefile | 1 - > xen/arch/arm/arm32/debug-exynos4210.inc | 77 +++++++++++++++++++++++++++++++ > 4 files changed, 82 insertions(+), 1 deletion(-) > create mode 100644 xen/arch/arm/arm32/debug-exynos4210.inc > > diff --git a/docs/misc/arm/early-printk.txt b/docs/misc/arm/early-printk.txt > index 4065811..d5cae85 100644 > --- a/docs/misc/arm/early-printk.txt > +++ b/docs/misc/arm/early-printk.txt > @@ -10,5 +10,6 @@ option should not be enable for Xens that are intended to be portable. > CONFIG_EARLY_PRINTK=mach > where mach is the name of the machine: > - vexpress: printk with pl011 for versatile express > + - exynos5250: printk with the second UART > > By default early printk is disabled. > diff --git a/xen/arch/arm/Rules.mk b/xen/arch/arm/Rules.mk > index 4af052c..cff834e 100644 > --- a/xen/arch/arm/Rules.mk > +++ b/xen/arch/arm/Rules.mk > @@ -47,6 +47,10 @@ ifeq ($(CONFIG_EARLY_PRINTK), vexpress) > EARLY_PRINTK := y > EARLY_PRINTK_INC := pl011 > endif > +ifeq ($(CONFIG_EARLY_PRINTK), exynos5250) > +EARLY_PRINTK := y > +EARLY_PRINTK_INC := exynos4210> +endif > > CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK > CFLAGS-$(EARLY_PRINTK) += -DEARLY_PRINTK_INC=\"debug-$(EARLY_PRINTK_INC).inc\"These are somewhat redundant, we could almost combine them into one which is the .inc file to use and then use ifdef on that.> diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile > index 6af8ca3..aaf277a 100644 > --- a/xen/arch/arm/arm32/Makefile > +++ b/xen/arch/arm/arm32/Makefile > @@ -8,4 +8,3 @@ obj-y += traps.o > obj-y += domain.o > > obj-$(EARLY_PRINTK) += debug.o > -obj-$(CONFIG_EARLY_PL011) += debug-pl011.oI think this shouldn''t have been added earlier and so shouldn''t need to be removed here.> diff --git a/xen/arch/arm/arm32/debug-exynos4210.inc b/xen/arch/arm/arm32/debug-exynos4210.inc > new file mode 100644 > index 0000000..17ee5f1 > --- /dev/null > +++ b/xen/arch/arm/arm32/debug-exynos4210.inc > @@ -0,0 +1,77 @@ > +/* > + * xen/arch/arm/arm32/debug-exynos4210.inc > + * > + * 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/exynos4210-uart.h> > + > +#define EARLY_UART_BASE_ADDRESS 0x12c20000 > + > +/* Exynos 5 UART initialization > + * rb: register which containts the UART base address"contains"> + * rc: scratch register 1 > + * rd: scratch register 2 */ > +.macro early_uart_init rb rc rd > + /* init clock */ > + ldr \rc, =0x10020000 > + /* select MPLL (800MHz) source clock */ > + ldr \rd, [\rc, #0x250] > + and \rd, \rd, #(~(0xf<<8)) > + orr \rd, \rd, #(0x6<<8) > + str \rd, [\rc, #0x250] > + /* ratio 800/(7+1) */ > + ldr \rd, [\rc, #0x558] > + and \rd, \rd, #(~(0xf<<8)) > + orr \rd, \rd, #(0x7<<8) > + str \rd, [\rc, #0x558] > + > + mov \rc, #4 > + str \rc, [\rb, #UFRACVAL] /* -> UFRACVAL (Baud divisor fraction) */ > + mov \rc, #53 > + str \rc, [\rb, #UBRDIV] /* -> UBRDIV (Baud divisor integer) */ > + mov \rc, #3 /* 8n1 */ > + str \rc, [\rb, #ULCON] /* -> (Line control) */ > + ldr \rc, =UCON_TX_IRQ /* TX IRQMODE */ > + str \rc, [\rb, #UCON] /* -> (Control Register) */ > + mov \rc, #0x0 > + str \rc, [\rb, #UFCON] /* disable FIFO */ > + mov \rc, #0x0 > + str \rc, [\rb, #UMCON] /* no auto flow control */ > +.endm > + > +/* Exynos 5 UART wait UART to be ready to transmit > + * rb: register which containts the UART base address"contains", again and twice more below.> + * rc: scratch register */ > +.macro early_uart_ready rb rc > +1: > + ldr \rc, [\rb, #UTRSTAT] /* <- UTRSTAT (Flag register) */ > + tst \rc, #UTRSTAT_TX_EMPTY /* Check BUSY bit */ > + beq 1b /* Wait for the UART to be ready */ > +.endm > + > +/* Exynos 5 UART transmit character > + * rb: register which containts the UART base address > + * rt: register which containts the character to transmit */ > +.macro early_uart_transmit rb rt > + str \rt, [\rb, #UTXH] /* -> UTXH (Data Register) */ > +.endm > + > +/* > + * Local variables: > + * mode: ASM > + * indent-tabs-mode: nil > + * End: > + */
Ian Campbell
2013-May-09 10:19 UTC
Re: [PATCH V2 31/33] xen/arm: Add platform specific code for the exynos5
On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote:> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Changes in v2: > - Add dom0 1:1 mapping quirk for the arndale board > - s/mapping/mappings/ in comment > - Remove debug trap (unnecessary with linux 3.9) > --- > xen/arch/arm/platforms/Makefile | 1 + > xen/arch/arm/platforms/exynos5.c | 86 +++++++++++++++++++++++++++++++ > xen/include/asm-arm/platforms/exynos5.h | 40 ++++++++++++++ > 3 files changed, 127 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..8620390 > --- /dev/null > +++ b/xen/arch/arm/platforms/exynos5.c > @@ -0,0 +1,86 @@ > +/* > + * 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 mappings for dom0 (Not in the DTS) */"Additional"> +static int exynos5_specific_mapping(struct domain *d) > +{ > + /* 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);If these get added to a future version of the DTS will badness ensue? I suppose all we can do is add a check for the new compatible node at that time, which we obviously can''t do now...> 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)Inconsistent indent, hard tabs perhaps?> + > +#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 */In a subsequent patch?> +#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-May-09 10:24 UTC
Re: [PATCH V2 32/33] xen/arm: WORKAROUND Support kick cpus and switch to hypervisor for the exynos5
On Wed, 2013-05-08 at 03:33 +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. > > Theses modifications aim to be removed as soon as possible. It should > be moved either in a platform specific boot-wrapper (which will be start > before Xen), or in the bootloader (assuming U-Boot/Grub will support SMP).With this proviso I''m OK with this change for 4.3, I''d like to see this gone for 4.4 though.> Signed-off-by: Julien Grall <julien.grall@linaro.org>Acked-by: Ian Campbell <ian.campbell@citrix.com>
Julien Grall
2013-May-09 13:03 UTC
Re: [PATCH V2 31/33] xen/arm: Add platform specific code for the exynos5
On 05/09/2013 11:19 AM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> Signed-off-by: Julien Grall <julien.grall@linaro.org> >> >> Changes in v2: >> - Add dom0 1:1 mapping quirk for the arndale board >> - s/mapping/mappings/ in comment >> - Remove debug trap (unnecessary with linux 3.9) >> --- >> xen/arch/arm/platforms/Makefile | 1 + >> xen/arch/arm/platforms/exynos5.c | 86 +++++++++++++++++++++++++++++++ >> xen/include/asm-arm/platforms/exynos5.h | 40 ++++++++++++++ >> 3 files changed, 127 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..8620390 >> --- /dev/null >> +++ b/xen/arch/arm/platforms/exynos5.c >> @@ -0,0 +1,86 @@ >> +/* >> + * 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 mappings for dom0 (Not in the DTS) */ > > "Additional" > >> +static int exynos5_specific_mapping(struct domain *d) >> +{ >> + /* 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); > > If these get added to a future version of the DTS will badness ensue? I > suppose all we can do is add a check for the new compatible node at that > time, which we obviously can''t do now...In this case, we can remove this both lines. map_devices_from_device_tree will do all the work. But I think it''s too specific to be added in the DTS.>> 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) > > Inconsistent indent, hard tabs perhaps?Right. Will be fix on the next patch series.>> + >> +#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 */ > > In a subsequent patch?Yes. It''s used in patch 32.>> +#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
Julien Grall
2013-May-09 13:14 UTC
Re: [PATCH V2 28/33] xen/arm: Don''t use pl011 UART by default for early printk
On 05/09/2013 11:10 AM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> 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 > > Is this correct now that you are using debug-pl011.inc?It comes from a bad merge. I will fix it on the next patch series.>> /* Print a 32-bit number in hex. Specific to the PL011 UART. >> * r0: Number to print. >> - * clobbers r0-r3 */ >> + * r11: Early UART base address >> + * clobbers r1-r3 */ > > This still clobbers r0, via the lsl below.Right will be fix on the next patch series.>> putn: >> 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: >> + early_uart_ready r11, r2 >> 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) */ >> + early_uart_transmit r11, r2 >> lsl r0, #4 /* Roll it through one nybble at a time */ >> subs r3, r3, #1 >> bne 1b >> @@ -329,51 +329,44 @@ 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. >> + * x23: Early UART base address >> + * Clobbers x0-x1 */ > > Does it actually clobber x1?Yes, by puts. init_uart will jump to this function at the end.>> 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) */ >> + early_uart_init x23, 0 >> adr x0, 1f >> - b puts >> + b puts /* Jump to puts */ >> 1: .asciz "- UART enabled -\r\n" >> .align 4 > > >-- Julien
Julien Grall
2013-May-09 14:32 UTC
Re: [PATCH V2 04/33] xen/arm: Bump early printk internal buffer to 512
On 05/08/2013 02:00 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> When debug is enabled in device tree code, some lines >> are bigger than 80 characters. >> >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > Acked-by: Ian Campbell <ian.campbell@citrix.com> > > Although if we can also take steps to not let the line length get too > long that would be valuable, I can see 80-100 being tolerable but if we > are actually seeing lines with 512 characters that is an issue in its > own right. I appreciate you''ve just picked a "big enough" number and we > hopefully aren''t seeing anything like 512 in practice.It seems, the function printk uses a buffer of 10024. It''s mainly when device tree prints full path on each node.>> Changes in v2: >> - Move buffer to a static variable >> --- >> xen/arch/arm/early_printk.c | 5 +++-- >> 1 file changed, 3 insertions(+), 2 deletions(-) >> >> diff --git a/xen/arch/arm/early_printk.c b/xen/arch/arm/early_printk.c >> index bdf4c0e..0f99a43 100644 >> --- a/xen/arch/arm/early_printk.c >> +++ b/xen/arch/arm/early_printk.c >> @@ -29,6 +29,9 @@ void __init early_putch(char c) >> *r = c; >> } >> >> +/* Early printk buffer */ >> +static char __initdata buf[512]; >> + >> static void __init early_puts(const char *s) >> { >> while (*s != ''\0'') { >> @@ -41,8 +44,6 @@ static void __init early_puts(const char *s) >> >> static void __init early_vprintk(const char *fmt, va_list args) >> { >> - char buf[80]; >> - >> vsnprintf(buf, sizeof(buf), fmt, args); >> early_puts(buf); >> } > >
Julien Grall
2013-May-09 14:38 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On 05/08/2013 04:34 PM, Ian Campbell wrote:> On Wed, 2013-05-08 at 16:15 +0100, Julien Grall wrote: >> On 05/08/2013 02:41 PM, Ian Campbell wrote: >> >>> On Wed, 2013-05-08 at 14:34 +0100, Julien Grall wrote: >>>>> Which only leaves ones which are both? How many are these? I''m inclined >>>>> towards suggesting that if they are debug prints which are disabled by >>>>> default and require a recompile to enable then the person doing the >>>>> debugging can select whether they care about early or late messages by >>>>> #define-ing DEBUG or EARLY_DEBUG or both as required. >>>> >>>> We can''t choose at compile time. Early printk function is in init code >>>> section. So at the end of boot the function will disappear. >>> >>> Oh, right. >>> >>> Perhaps something could be conditional on system_state >>> SYS_STATE_active, this happens not long before we discard the initial >>> sections. >> >> >> I think it''s too late. If we use early_printk until this stage, we will >> lose some usefull debug when early printk is disabled (ie most of the time). >> >> How about adding the missing system_state = SYS_STATE_boot just after >> console_init_preirq? Early printk will only be used when system_state =>> SYS_STATE_early_boot. > > I think this is a common thing so it''d need wider discussion.SYS_STATE_boot already exists for x86. We forgot to use it on Xen Arm. So all ARM boot is done with system_state equals to SYS_STATE_early_boot.> >>>> Device tree function could be called after the end of the boot. For the >>>> moment it''s not the case. >>>> >>>> The best solution would be: early_printk is directly handled in console >>>> as linux does. >>> >>> That does sound best. >> >> >> I will send a patch later for this. > > Does that make the above moot?Yes. I think this will avoid lots of headache to know if we need to use early_printk or printk in the code. It''s really annoying when Xen is stucked with no log because an assert, which uses printk, is raised when console is not setup. But this changes will impact x86. -- Julien
Ian Campbell
2013-May-09 14:43 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On Thu, 2013-05-09 at 15:38 +0100, Julien Grall wrote:> On 05/08/2013 04:34 PM, Ian Campbell wrote: > > > On Wed, 2013-05-08 at 16:15 +0100, Julien Grall wrote: > >> On 05/08/2013 02:41 PM, Ian Campbell wrote: > >> > >>> On Wed, 2013-05-08 at 14:34 +0100, Julien Grall wrote: > >>>>> Which only leaves ones which are both? How many are these? I''m inclined > >>>>> towards suggesting that if they are debug prints which are disabled by > >>>>> default and require a recompile to enable then the person doing the > >>>>> debugging can select whether they care about early or late messages by > >>>>> #define-ing DEBUG or EARLY_DEBUG or both as required. > >>>> > >>>> We can''t choose at compile time. Early printk function is in init code > >>>> section. So at the end of boot the function will disappear. > >>> > >>> Oh, right. > >>> > >>> Perhaps something could be conditional on system_state > >>> SYS_STATE_active, this happens not long before we discard the initial > >>> sections. > >> > >> > >> I think it''s too late. If we use early_printk until this stage, we will > >> lose some usefull debug when early printk is disabled (ie most of the time). > >> > >> How about adding the missing system_state = SYS_STATE_boot just after > >> console_init_preirq? Early printk will only be used when system_state => >> SYS_STATE_early_boot. > > > > I think this is a common thing so it''d need wider discussion. > > > SYS_STATE_boot already exists for x86. We forgot to use it on Xen Arm. > So all ARM boot is done with system_state equals to SYS_STATE_early_boot.Oh, then great lets use that ;-)> >>>> Device tree function could be called after the end of the boot. For the > >>>> moment it''s not the case. > >>>> > >>>> The best solution would be: early_printk is directly handled in console > >>>> as linux does. > >>> > >>> That does sound best. > >> > >> > >> I will send a patch later for this. > > > > Does that make the above moot? > > > Yes. I think this will avoid lots of headache to know if we need to use > early_printk or printk in the code. It''s really annoying when Xen is > stucked with no log because an assert, which uses printk, is raised when > console is not setup. But this changes will impact x86.Yes, this is probably 4.4 material then?
Ian Campbell
2013-May-09 14:46 UTC
Re: [PATCH V2 04/33] xen/arm: Bump early printk internal buffer to 512
On Thu, 2013-05-09 at 15:32 +0100, Julien Grall wrote:> On 05/08/2013 02:00 PM, Ian Campbell wrote: > > > On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: > >> When debug is enabled in device tree code, some lines > >> are bigger than 80 characters. > >> > >> Signed-off-by: Julien Grall <julien.grall@linaro.org> > > > > Acked-by: Ian Campbell <ian.campbell@citrix.com> > > > > Although if we can also take steps to not let the line length get too > > long that would be valuable, I can see 80-100 being tolerable but if we > > are actually seeing lines with 512 characters that is an issue in its > > own right. I appreciate you''ve just picked a "big enough" number and we > > hopefully aren''t seeing anything like 512 in practice. > > > It seems, the function printk uses a buffer of 10024.I suppose the extra 0 is a typo, but even 1024 seems excessive!> It''s mainly when device tree prints full path on each node.OK, lets leave it for now but maybe at some point think about ways of shortening these lines since even if we print them they are going to be wrapped and hard to read. Perhaps indenting children instead of printing the whole path.
Julien Grall
2013-May-09 14:55 UTC
Re: [PATCH V2 07/33] xen/arm: Create a hierarchical device tree
On 05/09/2013 03:43 PM, Ian Campbell wrote:> On Thu, 2013-05-09 at 15:38 +0100, Julien Grall wrote: >> On 05/08/2013 04:34 PM, Ian Campbell wrote: >> >>> On Wed, 2013-05-08 at 16:15 +0100, Julien Grall wrote: >>>> On 05/08/2013 02:41 PM, Ian Campbell wrote: >>>> >>>>> On Wed, 2013-05-08 at 14:34 +0100, Julien Grall wrote: >>>>>>> Which only leaves ones which are both? How many are these? I''m inclined >>>>>>> towards suggesting that if they are debug prints which are disabled by >>>>>>> default and require a recompile to enable then the person doing the >>>>>>> debugging can select whether they care about early or late messages by >>>>>>> #define-ing DEBUG or EARLY_DEBUG or both as required. >>>>>> >>>>>> We can''t choose at compile time. Early printk function is in init code >>>>>> section. So at the end of boot the function will disappear. >>>>> >>>>> Oh, right. >>>>> >>>>> Perhaps something could be conditional on system_state >>>>> SYS_STATE_active, this happens not long before we discard the initial >>>>> sections. >>>> >>>> >>>> I think it''s too late. If we use early_printk until this stage, we will >>>> lose some usefull debug when early printk is disabled (ie most of the time). >>>> >>>> How about adding the missing system_state = SYS_STATE_boot just after >>>> console_init_preirq? Early printk will only be used when system_state =>>>> SYS_STATE_early_boot. >>> >>> I think this is a common thing so it''d need wider discussion. >> >> >> SYS_STATE_boot already exists for x86. We forgot to use it on Xen Arm. >> So all ARM boot is done with system_state equals to SYS_STATE_early_boot. > > Oh, then great lets use that ;-) > >>>>>> Device tree function could be called after the end of the boot. For the >>>>>> moment it''s not the case. >>>>>> >>>>>> The best solution would be: early_printk is directly handled in console >>>>>> as linux does. >>>>> >>>>> That does sound best. >>>> >>>> >>>> I will send a patch later for this. >>> >>> Does that make the above moot? >> >> >> Yes. I think this will avoid lots of headache to know if we need to use >> early_printk or printk in the code. It''s really annoying when Xen is >> stucked with no log because an assert, which uses printk, is raised when >> console is not setup. But this changes will impact x86. > > Yes, this is probably 4.4 material then?Yes, I will write a line on this issue with ASSERT on the wiki. -- Julien
Julien Grall
2013-May-09 18:33 UTC
Re: [PATCH V2 29/33] xen/arm: Add exynos 4210 UART support
On 05/09/2013 11:13 AM, Ian Campbell wrote:> On Wed, 2013-05-08 at 03:33 +0100, Julien Grall wrote: >> + /* TODO: should be updated */ >> + /* Baud rate already set: read it out from the divisor latch. */ >> +#if 0 >> + divisor = (uart->regs[IBRD] << 6) | uart->regs[FBRD]; >> + uart->baud = (uart->clock_hz << 2) / divisor; >> +#endif > > Can we drop the #if 0, extending the comment if necessary, or if > possible drop the whole thing.I will move this two lines in the comment.>> +static int __init exynos4210_uart_init(struct dt_device_node *dev, >> + const void *data) >> +{ >> + const struct serial_arm_defaults *defaults = data; >> + struct exynos4210_uart *uart; >> + int res; >> + >> + if ( (defaults->index < 0) || (defaults->index > 1) ) >> + return -EINVAL; >> + >> + uart = &exynos4210_com[defaults->index]; >> + >> + /* uart->clock_hz = 0x16e3600; */ >> + uart->baud = BAUD_AUTO;//115200; > > Drop the //115200.Will be fixed in the next patch series.>> diff --git a/xen/include/asm-arm/exynos4210-uart.h b/xen/include/asm-arm/exynos4210-uart.h >> new file mode 100644 >> index 0000000..1527521 >> --- /dev/null >> +++ b/xen/include/asm-arm/exynos4210-uart.h >> @@ -0,0 +1,111 @@ >> +/* >> + * xen/include/asm-arm/exynos4210-uart.h >> + * >> + * Common constant definition between ealry printk and the UART driver > > "early" > > If you fix all the above then > Acked-by: Ian Campbell <ian.campbell@citrix.com> > > Ian. >