Message ID | 1478636499-14339-7-git-send-email-drjones@redhat.com |
---|---|
State | Superseded |
Headers | show |
Hi, On 08/11/16 20:21, Andrew Jones wrote: > Add some gicv2 support. This just adds init and enable > functions, allowing unit tests to start messing with it. > > Signed-off-by: Andrew Jones <drjones@redhat.com> > > --- > v4: > - only take defines from kernel we need now [Andre] > - moved defines to asm/gic.h so they'll be shared with v3 [drew] > - simplify enable by not caring if we reinit the distributor [drew] > - init all GICD_INT_DEF_PRI_X4 registers [Eric] > --- > arm/Makefile.common | 1 + > lib/arm/asm/gic-v2.h | 28 +++++++++++++++++++ > lib/arm/asm/gic.h | 44 +++++++++++++++++++++++++++++ > lib/arm/gic.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ > lib/arm64/asm/gic-v2.h | 1 + > lib/arm64/asm/gic.h | 1 + > 6 files changed, 150 insertions(+) > create mode 100644 lib/arm/asm/gic-v2.h > create mode 100644 lib/arm/asm/gic.h > create mode 100644 lib/arm/gic.c > create mode 100644 lib/arm64/asm/gic-v2.h > create mode 100644 lib/arm64/asm/gic.h > > diff --git a/arm/Makefile.common b/arm/Makefile.common > index ccb554d9251a..41239c37e092 100644 > --- a/arm/Makefile.common > +++ b/arm/Makefile.common > @@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o > cflatobjs += lib/arm/bitops.o > cflatobjs += lib/arm/psci.o > cflatobjs += lib/arm/smp.o > +cflatobjs += lib/arm/gic.o > > libeabi = lib/arm/libeabi.a > eabiobjs = lib/arm/eabi_compat.o > diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h > new file mode 100644 > index 000000000000..f91530f88355 > --- /dev/null > +++ b/lib/arm/asm/gic-v2.h > @@ -0,0 +1,28 @@ > +/* > + * All GIC* defines are lifted from include/linux/irqchip/arm-gic.h > + * > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#ifndef _ASMARM_GIC_V2_H_ > +#define _ASMARM_GIC_V2_H_ > + > +#ifndef _ASMARM_GIC_H_ > +#error Do not directly include <asm/gic-v2.h>. Include <asm/gic.h> > +#endif > + > +struct gicv2_data { > + void *dist_base; > + void *cpu_base; > + unsigned int irq_nr; > +}; > +extern struct gicv2_data gicv2_data; > + > +#define gicv2_dist_base() (gicv2_data.dist_base) > +#define gicv2_cpu_base() (gicv2_data.cpu_base) > + > +extern int gicv2_init(void); > +extern void gicv2_enable_defaults(void); > + > +#endif /* _ASMARM_GIC_V2_H_ */ > diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h > new file mode 100644 > index 000000000000..ec92f1064dc0 > --- /dev/null > +++ b/lib/arm/asm/gic.h > @@ -0,0 +1,44 @@ > +/* > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#ifndef _ASMARM_GIC_H_ > +#define _ASMARM_GIC_H_ > + > +#include <asm/gic-v2.h> > + > +#define GIC_CPU_CTRL 0x00 > +#define GIC_CPU_PRIMASK 0x04 > + > +#define GICC_ENABLE 0x1 > +#define GICC_INT_PRI_THRESHOLD 0xf0 > + > +#define GIC_DIST_CTRL 0x000 > +#define GIC_DIST_CTR 0x004 I think we shouldn't copy this old name here, which stems from pre-GICv2 times (PL390?), IIUC. Both GIC specs talk of TYPER here. Also if we now use the same defines for both the GICv2 and GICv3 distributor, we should really stick with the (modern) spec naming, which is GICD_CTRL, GICD_TYPER and so on. Same for the CPU interface (GICC_CTRL). In the kernel these names are used for GICv3, but we didn't bother to adjust the existing GICv2 names to avoid pointless churn. Also that would line up with the bit field defines below. Cheers, Andre. > +#define GIC_DIST_ENABLE_SET 0x100 > +#define GIC_DIST_PRI 0x400 > + > +#define GICD_ENABLE 0x1 > +#define GICD_INT_EN_SET_SGI 0x0000ffff > +#define GICD_INT_DEF_PRI 0xa0 > +#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\ > + (GICD_INT_DEF_PRI << 16) |\ > + (GICD_INT_DEF_PRI << 8) |\ > + GICD_INT_DEF_PRI) > + > +#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) > + > +#ifndef __ASSEMBLY__ > + > +/* > + * gic_init will try to find all known gics, and then > + * initialize the gic data for the one found. > + * returns > + * 0 : no gic was found > + * > 0 : the gic version of the gic found > + */ > +extern int gic_init(void); > + > +#endif /* !__ASSEMBLY__ */ > +#endif /* _ASMARM_GIC_H_ */ > diff --git a/lib/arm/gic.c b/lib/arm/gic.c > new file mode 100644 > index 000000000000..91d78c9a0cc2 > --- /dev/null > +++ b/lib/arm/gic.c > @@ -0,0 +1,75 @@ > +/* > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#include <devicetree.h> > +#include <asm/gic.h> > +#include <asm/io.h> > + > +struct gicv2_data gicv2_data; > + > +/* > + * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt > + */ > +static bool > +gic_get_dt_bases(const char *compatible, void **base1, void **base2) > +{ > + struct dt_pbus_reg reg; > + struct dt_device gic; > + struct dt_bus bus; > + int node, ret; > + > + dt_bus_init_defaults(&bus); > + dt_device_init(&gic, &bus, NULL); > + > + node = dt_device_find_compatible(&gic, compatible); > + assert(node >= 0 || node == -FDT_ERR_NOTFOUND); > + > + if (node == -FDT_ERR_NOTFOUND) > + return false; > + > + dt_device_bind_node(&gic, node); > + > + ret = dt_pbus_translate(&gic, 0, ®); > + assert(ret == 0); > + *base1 = ioremap(reg.addr, reg.size); > + > + ret = dt_pbus_translate(&gic, 1, ®); > + assert(ret == 0); > + *base2 = ioremap(reg.addr, reg.size); > + > + return true; > +} > + > +int gicv2_init(void) > +{ > + return gic_get_dt_bases("arm,cortex-a15-gic", > + &gicv2_data.dist_base, &gicv2_data.cpu_base); > +} > + > +int gic_init(void) > +{ > + if (gicv2_init()) > + return 2; > + return 0; > +} > + > +void gicv2_enable_defaults(void) > +{ > + void *dist = gicv2_dist_base(); > + void *cpu_base = gicv2_cpu_base(); > + unsigned int i; > + > + gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GIC_DIST_CTR)); > + if (gicv2_data.irq_nr > 1020) > + gicv2_data.irq_nr = 1020; > + > + for (i = 0; i < gicv2_data.irq_nr; i += 4) > + writel(GICD_INT_DEF_PRI_X4, dist + i + GIC_DIST_PRI); > + > + writel(GICD_INT_EN_SET_SGI, dist + GIC_DIST_ENABLE_SET); > + writel(GICD_ENABLE, dist + GIC_DIST_CTRL); > + writel(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK); > + writel(GICC_ENABLE, cpu_base + GIC_CPU_CTRL); > +} > diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h > new file mode 100644 > index 000000000000..52226624a209 > --- /dev/null > +++ b/lib/arm64/asm/gic-v2.h > @@ -0,0 +1 @@ > +#include "../../arm/asm/gic-v2.h" > diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h > new file mode 100644 > index 000000000000..e5eb302a31b4 > --- /dev/null > +++ b/lib/arm64/asm/gic.h > @@ -0,0 +1 @@ > +#include "../../arm/asm/gic.h" >
On Wed, Nov 09, 2016 at 11:53:39AM +0000, Andre Przywara wrote: [...] > > diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h > > new file mode 100644 > > index 000000000000..ec92f1064dc0 > > --- /dev/null > > +++ b/lib/arm/asm/gic.h > > @@ -0,0 +1,44 @@ > > +/* > > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > > + * > > + * This work is licensed under the terms of the GNU LGPL, version 2. > > + */ > > +#ifndef _ASMARM_GIC_H_ > > +#define _ASMARM_GIC_H_ > > + > > +#include <asm/gic-v2.h> > > + > > +#define GIC_CPU_CTRL 0x00 > > +#define GIC_CPU_PRIMASK 0x04 > > + > > +#define GICC_ENABLE 0x1 > > +#define GICC_INT_PRI_THRESHOLD 0xf0 > > + > > +#define GIC_DIST_CTRL 0x000 > > +#define GIC_DIST_CTR 0x004 > > I think we shouldn't copy this old name here, which stems from pre-GICv2 > times (PL390?), IIUC. Both GIC specs talk of TYPER here. > > Also if we now use the same defines for both the GICv2 and GICv3 > distributor, we should really stick with the (modern) spec naming, which > is GICD_CTRL, GICD_TYPER and so on. Same for the CPU interface (GICC_CTRL). > In the kernel these names are used for GICv3, but we didn't bother to > adjust the existing GICv2 names to avoid pointless churn. > Also that would line up with the bit field defines below. > Yeah, I noticed the CTR vs. TYPER naming weirdness. I considered exclusively defining the gicv3/modern/better name, but wasn't sure I should deviate from the kernel names. Keeping the names consistent is nice for grepping kernel sources, which needs to be done when a test fails and we want to find the bug. I'd personally prefer "pointless" churn in the kernel to get it straightened out there. If it ever is, then I'd obviously update this code too. Until then, I think maintaining easy greppability is the better choice. Thanks, drew
diff --git a/arm/Makefile.common b/arm/Makefile.common index ccb554d9251a..41239c37e092 100644 --- a/arm/Makefile.common +++ b/arm/Makefile.common @@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o cflatobjs += lib/arm/bitops.o cflatobjs += lib/arm/psci.o cflatobjs += lib/arm/smp.o +cflatobjs += lib/arm/gic.o libeabi = lib/arm/libeabi.a eabiobjs = lib/arm/eabi_compat.o diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h new file mode 100644 index 000000000000..f91530f88355 --- /dev/null +++ b/lib/arm/asm/gic-v2.h @@ -0,0 +1,28 @@ +/* + * All GIC* defines are lifted from include/linux/irqchip/arm-gic.h + * + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#ifndef _ASMARM_GIC_V2_H_ +#define _ASMARM_GIC_V2_H_ + +#ifndef _ASMARM_GIC_H_ +#error Do not directly include <asm/gic-v2.h>. Include <asm/gic.h> +#endif + +struct gicv2_data { + void *dist_base; + void *cpu_base; + unsigned int irq_nr; +}; +extern struct gicv2_data gicv2_data; + +#define gicv2_dist_base() (gicv2_data.dist_base) +#define gicv2_cpu_base() (gicv2_data.cpu_base) + +extern int gicv2_init(void); +extern void gicv2_enable_defaults(void); + +#endif /* _ASMARM_GIC_V2_H_ */ diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h new file mode 100644 index 000000000000..ec92f1064dc0 --- /dev/null +++ b/lib/arm/asm/gic.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#ifndef _ASMARM_GIC_H_ +#define _ASMARM_GIC_H_ + +#include <asm/gic-v2.h> + +#define GIC_CPU_CTRL 0x00 +#define GIC_CPU_PRIMASK 0x04 + +#define GICC_ENABLE 0x1 +#define GICC_INT_PRI_THRESHOLD 0xf0 + +#define GIC_DIST_CTRL 0x000 +#define GIC_DIST_CTR 0x004 +#define GIC_DIST_ENABLE_SET 0x100 +#define GIC_DIST_PRI 0x400 + +#define GICD_ENABLE 0x1 +#define GICD_INT_EN_SET_SGI 0x0000ffff +#define GICD_INT_DEF_PRI 0xa0 +#define GICD_INT_DEF_PRI_X4 ((GICD_INT_DEF_PRI << 24) |\ + (GICD_INT_DEF_PRI << 16) |\ + (GICD_INT_DEF_PRI << 8) |\ + GICD_INT_DEF_PRI) + +#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) + +#ifndef __ASSEMBLY__ + +/* + * gic_init will try to find all known gics, and then + * initialize the gic data for the one found. + * returns + * 0 : no gic was found + * > 0 : the gic version of the gic found + */ +extern int gic_init(void); + +#endif /* !__ASSEMBLY__ */ +#endif /* _ASMARM_GIC_H_ */ diff --git a/lib/arm/gic.c b/lib/arm/gic.c new file mode 100644 index 000000000000..91d78c9a0cc2 --- /dev/null +++ b/lib/arm/gic.c @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#include <devicetree.h> +#include <asm/gic.h> +#include <asm/io.h> + +struct gicv2_data gicv2_data; + +/* + * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt + */ +static bool +gic_get_dt_bases(const char *compatible, void **base1, void **base2) +{ + struct dt_pbus_reg reg; + struct dt_device gic; + struct dt_bus bus; + int node, ret; + + dt_bus_init_defaults(&bus); + dt_device_init(&gic, &bus, NULL); + + node = dt_device_find_compatible(&gic, compatible); + assert(node >= 0 || node == -FDT_ERR_NOTFOUND); + + if (node == -FDT_ERR_NOTFOUND) + return false; + + dt_device_bind_node(&gic, node); + + ret = dt_pbus_translate(&gic, 0, ®); + assert(ret == 0); + *base1 = ioremap(reg.addr, reg.size); + + ret = dt_pbus_translate(&gic, 1, ®); + assert(ret == 0); + *base2 = ioremap(reg.addr, reg.size); + + return true; +} + +int gicv2_init(void) +{ + return gic_get_dt_bases("arm,cortex-a15-gic", + &gicv2_data.dist_base, &gicv2_data.cpu_base); +} + +int gic_init(void) +{ + if (gicv2_init()) + return 2; + return 0; +} + +void gicv2_enable_defaults(void) +{ + void *dist = gicv2_dist_base(); + void *cpu_base = gicv2_cpu_base(); + unsigned int i; + + gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GIC_DIST_CTR)); + if (gicv2_data.irq_nr > 1020) + gicv2_data.irq_nr = 1020; + + for (i = 0; i < gicv2_data.irq_nr; i += 4) + writel(GICD_INT_DEF_PRI_X4, dist + i + GIC_DIST_PRI); + + writel(GICD_INT_EN_SET_SGI, dist + GIC_DIST_ENABLE_SET); + writel(GICD_ENABLE, dist + GIC_DIST_CTRL); + writel(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK); + writel(GICC_ENABLE, cpu_base + GIC_CPU_CTRL); +} diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h new file mode 100644 index 000000000000..52226624a209 --- /dev/null +++ b/lib/arm64/asm/gic-v2.h @@ -0,0 +1 @@ +#include "../../arm/asm/gic-v2.h" diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h new file mode 100644 index 000000000000..e5eb302a31b4 --- /dev/null +++ b/lib/arm64/asm/gic.h @@ -0,0 +1 @@ +#include "../../arm/asm/gic.h"
Add some gicv2 support. This just adds init and enable functions, allowing unit tests to start messing with it. Signed-off-by: Andrew Jones <drjones@redhat.com> --- v4: - only take defines from kernel we need now [Andre] - moved defines to asm/gic.h so they'll be shared with v3 [drew] - simplify enable by not caring if we reinit the distributor [drew] - init all GICD_INT_DEF_PRI_X4 registers [Eric] --- arm/Makefile.common | 1 + lib/arm/asm/gic-v2.h | 28 +++++++++++++++++++ lib/arm/asm/gic.h | 44 +++++++++++++++++++++++++++++ lib/arm/gic.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/arm64/asm/gic-v2.h | 1 + lib/arm64/asm/gic.h | 1 + 6 files changed, 150 insertions(+) create mode 100644 lib/arm/asm/gic-v2.h create mode 100644 lib/arm/asm/gic.h create mode 100644 lib/arm/gic.c create mode 100644 lib/arm64/asm/gic-v2.h create mode 100644 lib/arm64/asm/gic.h -- 2.7.4