mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
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. Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> Committed-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
1 parent
d27df53809
commit
01dedfbcdf
3 files changed
+107
-14
No files matched your search
+29
-11
@@ -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,28 @@ 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;
|
||||
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;
|
||||
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 +587,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)
|
||||
|
||||
@@ -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 ( !strcmp(prop, match) )
|
||||
return 1;
|
||||
l = strlen(prop) + 1;
|
||||
prop += l;
|
||||
len -= l;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int device_tree_nr_reg_ranges(const struct fdt_property *prop,
|
||||
u32 address_cells, u32 size_cells)
|
||||
{
|
||||
u32 reg_cells = address_cells + size_cells;
|
||||
return 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));
|
||||
banks = device_tree_nr_reg_ranges(prop, address_cells, size_cells);
|
||||
|
||||
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;
|
||||
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 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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||