diff mbox

[kvm-unit-tests,v4,06/11] arm/arm64: add initial gicv2 support

Message ID 1478636499-14339-7-git-send-email-drjones@redhat.com
State Superseded
Headers show

Commit Message

Andrew Jones Nov. 8, 2016, 8:21 p.m. UTC
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

Comments

Andre Przywara Nov. 9, 2016, 11:53 a.m. UTC | #1
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, &reg);

> +	assert(ret == 0);

> +	*base1 = ioremap(reg.addr, reg.size);

> +

> +	ret = dt_pbus_translate(&gic, 1, &reg);

> +	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"

>
Andrew Jones Nov. 9, 2016, 12:06 p.m. UTC | #2
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 mbox

Patch

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, &reg);
+	assert(ret == 0);
+	*base1 = ioremap(reg.addr, reg.size);
+
+	ret = dt_pbus_translate(&gic, 1, &reg);
+	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"