[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v2] xen: get GIC addresses from DT
Get the address of the GIC distributor, cpu, virtual and virtual cpu interfaces registers from device tree. Note: I couldn't completely get rid of GIC_BASE_ADDRESS, GIC_DR_OFFSET and friends because we are using them from mode_switch.S, that is executed before device tree has been parsed. But at least mode_switch.S is known to contain vexpress specific code anyway. Changes in v2: - remove 2 superflous lines from process_gic_node; - introduce device_tree_get_reg_ranges; - add a check for uninitialized GIC interface addresses; - add a check for non-page aligned GIC interface addresses; - remove the code to deal with non-page aligned addresses from GICC and GICH. Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx> diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c index 0c6fab9..2b29e7e 100644 --- a/xen/arch/arm/gic.c +++ b/xen/arch/arm/gic.c @@ -26,6 +26,7 @@ #include <xen/errno.h> #include <xen/softirq.h> #include <xen/list.h> +#include <xen/device_tree.h> #include <asm/p2m.h> #include <asm/domain.h> @@ -33,10 +34,8 @@ /* Access to the GIC Distributor registers through the fixmap */ #define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD)) -#define GICC ((volatile uint32_t *) (FIXMAP_ADDR(FIXMAP_GICC1) \ - + (GIC_CR_OFFSET & 0xfff))) -#define GICH ((volatile uint32_t *) (FIXMAP_ADDR(FIXMAP_GICH) \ - + (GIC_HR_OFFSET & 0xfff))) +#define GICC ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICC1)) +#define GICH ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICH)) static void gic_restore_pending_irqs(struct vcpu *v); /* Global state */ @@ -44,6 +43,7 @@ static struct { paddr_t dbase; /* Address of distributor registers */ paddr_t cbase; /* Address of CPU interface registers */ paddr_t hbase; /* Address of virtual interface registers */ + paddr_t vbase; /* Address of virtual cpu interface registers */ unsigned int lines; unsigned int cpus; spinlock_t lock; @@ -306,10 +306,27 @@ static void __cpuinit gic_hyp_disable(void) /* Set up the GIC */ void __init gic_init(void) { - /* XXX FIXME get this from devicetree */ - gic.dbase = GIC_BASE_ADDRESS + GIC_DR_OFFSET; - gic.cbase = GIC_BASE_ADDRESS + GIC_CR_OFFSET; - gic.hbase = GIC_BASE_ADDRESS + GIC_HR_OFFSET; + 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" + " 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 & ~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("error: 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; set_fixmap(FIXMAP_GICD, gic.dbase >> PAGE_SHIFT, DEV_SHARED); BUILD_BUG_ON(FIXMAP_ADDR(FIXMAP_GICC1) != FIXMAP_ADDR(FIXMAP_GICC2)-PAGE_SIZE); @@ -569,9 +586,9 @@ int gicv_setup(struct domain *d) { /* map the gic virtual cpu interface in the gic cpu interface region of * the guest */ - return map_mmio_regions(d, GIC_BASE_ADDRESS + GIC_CR_OFFSET, - GIC_BASE_ADDRESS + GIC_CR_OFFSET + (2 * PAGE_SIZE) - 1, - GIC_BASE_ADDRESS + GIC_VR_OFFSET); + return map_mmio_regions(d, gic.cbase, + gic.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/common/device_tree.c b/xen/common/device_tree.c index da0af77..8d5b6b0 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -54,6 +54,33 @@ bool_t device_tree_type_matches(const void *fdt, int node, const char *match) return !strncmp(prop, match, len); } +bool_t device_tree_node_compatible(const void *fdt, int node, const char *match) +{ + int len, l; + const void *prop; + + prop = fdt_getprop(fdt, node, "compatible", &len); + if ( prop == NULL ) + return 0; + + while ( len > 0 ) { + if ( !strncmp(prop, match, strlen(match)) ) + return 1; + l = strlen(prop) + 1; + prop += l; + len -= l; + } + + return 0; +} + +static void device_tree_get_reg_ranges(const struct fdt_property *prop, + u32 address_cells, u32 size_cells, int *ranges) +{ + u32 reg_cells = address_cells + size_cells; + *ranges = fdt32_to_cpu(prop->len) / (reg_cells * sizeof(u32)); +} + static void __init get_val(const u32 **cell, u32 cells, u64 *val) { *val = 0; @@ -209,7 +236,6 @@ static void __init process_memory_node(const void *fdt, int node, u32 address_cells, u32 size_cells) { const struct fdt_property *prop; - size_t reg_cells; int i; int banks; const u32 *cell; @@ -230,8 +256,7 @@ static void __init process_memory_node(const void *fdt, int node, } cell = (const u32 *)prop->data; - reg_cells = address_cells + size_cells; - banks = fdt32_to_cpu(prop->len) / (reg_cells * sizeof(u32)); + device_tree_get_reg_ranges(prop, address_cells, size_cells, &banks); for ( i = 0; i < banks && early_info.mem.nr_banks < NR_MEM_BANKS; i++ ) { @@ -270,6 +295,46 @@ 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; + device_tree_get_reg_ranges(prop, address_cells, size_cells, &interfaces); + if ( interfaces < 4 ) + { + early_printk("fdt: node `%s': invalid `reg' property\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 int __init early_scan_node(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, @@ -279,6 +344,8 @@ 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); return 0; } diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 4d010c0..a0e3a97 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -26,8 +26,16 @@ 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_early_info { struct dt_mem_info mem; + struct dt_gic_info gic; }; typedef int (*device_tree_node_func)(const void *fdt, _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |