aboutsummaryrefslogtreecommitdiff
path: root/sys/arm64/arm64/mp_machdep.c
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2016-05-16 10:48:51 +0000
committerAndrew Turner <andrew@FreeBSD.org>2016-05-16 10:48:51 +0000
commit72b3f638b7c636284f808a03db1d72edada94b4a (patch)
treec7a2885a17ef9a6192ca3d5096e1696f250b2981 /sys/arm64/arm64/mp_machdep.c
parent4e1763d34c54dc9043778cadc41d38ce9f54c415 (diff)
downloadsrc-72b3f638b7c636284f808a03db1d72edada94b4a.tar.gz
src-72b3f638b7c636284f808a03db1d72edada94b4a.zip
Add support for intrng to arm64. As the GICv3 drivers will need to be
updated, and until further testing can be done, this is disabled for now. It is expected arm64 will switch to this interface, and the old interface will be removed before 11.0 is released. Obtained from: ABT Systems Ltd Relnotes: yes Sponsored by: The FreeBSD Foundation
Notes
Notes: svn path=/head/; revision=299936
Diffstat (limited to 'sys/arm64/arm64/mp_machdep.c')
-rw-r--r--sys/arm64/arm64/mp_machdep.c248
1 files changed, 247 insertions, 1 deletions
diff --git a/sys/arm64/arm64/mp_machdep.c b/sys/arm64/arm64/mp_machdep.c
index 22c99ba0ed6b..df9afdc55b43 100644
--- a/sys/arm64/arm64/mp_machdep.c
+++ b/sys/arm64/arm64/mp_machdep.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 The FreeBSD Foundation
+ * Copyright (c) 2015-2016 The FreeBSD Foundation
* All rights reserved.
*
* This software was developed by Andrew Turner under
@@ -65,6 +65,29 @@ __FBSDID("$FreeBSD$");
#include <dev/psci/psci.h>
+#ifdef INTRNG
+#include "pic_if.h"
+
+typedef void intr_ipi_send_t(void *, cpuset_t, u_int);
+typedef void intr_ipi_handler_t(void *);
+
+#define INTR_IPI_NAMELEN (MAXCOMLEN + 1)
+struct intr_ipi {
+ intr_ipi_handler_t * ii_handler;
+ void * ii_handler_arg;
+ intr_ipi_send_t * ii_send;
+ void * ii_send_arg;
+ char ii_name[INTR_IPI_NAMELEN];
+ u_long * ii_count;
+};
+
+static struct intr_ipi ipi_sources[INTR_IPI_COUNT];
+
+static struct intr_ipi *intr_ipi_lookup(u_int);
+static void intr_pic_ipi_setup(u_int, const char *, intr_ipi_handler_t *,
+ void *);
+#endif /* INTRNG */
+
boolean_t ofw_cpu_reg(phandle_t node, u_int, cell_t *);
extern struct pcpu __pcpu[];
@@ -184,9 +207,18 @@ release_aps(void *dummy __unused)
{
int cpu, i;
+#ifdef INTRNG
+ intr_pic_ipi_setup(IPI_AST, "ast", ipi_ast, NULL);
+ intr_pic_ipi_setup(IPI_PREEMPT, "preempt", ipi_preempt, NULL);
+ intr_pic_ipi_setup(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL);
+ intr_pic_ipi_setup(IPI_STOP, "stop", ipi_stop, NULL);
+ intr_pic_ipi_setup(IPI_STOP_HARD, "stop hard", ipi_stop, NULL);
+ intr_pic_ipi_setup(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL);
+#else
/* Setup the IPI handler */
for (i = 0; i < INTR_IPI_COUNT; i++)
arm_setup_ipihandler(ipi_handler, i);
+#endif
atomic_store_rel_int(&aps_ready, 1);
/* Wake up the other CPUs */
@@ -214,7 +246,9 @@ void
init_secondary(uint64_t cpu)
{
struct pcpu *pcpup;
+#ifndef INTRNG
int i;
+#endif
pcpup = &__pcpu[cpu];
/*
@@ -241,11 +275,13 @@ init_secondary(uint64_t cpu)
*/
identify_cpu();
+#ifndef INTRNG
/* Configure the interrupt controller */
arm_init_secondary();
for (i = 0; i < INTR_IPI_COUNT; i++)
arm_unmask_ipi(i);
+#endif
/* Start per-CPU event timers. */
cpu_initclocks_ap();
@@ -270,6 +306,10 @@ init_secondary(uint64_t cpu)
mtx_unlock_spin(&ap_boot_mtx);
+#ifdef INTRNG
+ intr_pic_init_secondary();
+#endif
+
/* Enter the scheduler */
sched_throw(NULL);
@@ -277,6 +317,64 @@ init_secondary(uint64_t cpu)
/* NOTREACHED */
}
+#ifdef INTRNG
+/*
+ * Send IPI thru interrupt controller.
+ */
+static void
+pic_ipi_send(void *arg, cpuset_t cpus, u_int ipi)
+{
+
+ KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+ PIC_IPI_SEND(intr_irq_root_dev, arg, cpus, ipi);
+}
+
+/*
+ * Setup IPI handler on interrupt controller.
+ *
+ * Not SMP coherent.
+ */
+static void
+intr_pic_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
+ void *arg)
+{
+ struct intr_irqsrc *isrc;
+ struct intr_ipi *ii;
+ int error;
+
+ KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+ KASSERT(hand != NULL, ("%s: ipi %u no handler", __func__, ipi));
+
+ error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, &isrc);
+ if (error != 0)
+ return;
+
+ isrc->isrc_handlers++;
+
+ ii = intr_ipi_lookup(ipi);
+ KASSERT(ii->ii_count == NULL, ("%s: ipi %u reused", __func__, ipi));
+
+ ii->ii_handler = hand;
+ ii->ii_handler_arg = arg;
+ ii->ii_send = pic_ipi_send;
+ ii->ii_send_arg = isrc;
+ strlcpy(ii->ii_name, name, INTR_IPI_NAMELEN);
+ ii->ii_count = intr_ipi_setup_counters(name);
+}
+
+static void
+intr_ipi_send(cpuset_t cpus, u_int ipi)
+{
+ struct intr_ipi *ii;
+
+ ii = intr_ipi_lookup(ipi);
+ if (ii->ii_count == NULL)
+ panic("%s: not setup IPI %u", __func__, ipi);
+
+ ii->ii_send(ii->ii_send_arg, cpus, ipi);
+}
+#endif
+
static void
ipi_ast(void *dummy __unused)
{
@@ -329,6 +427,7 @@ ipi_stop(void *dummy __unused)
CTR0(KTR_SMP, "IPI_STOP (restart)");
}
+#ifndef INTRNG
static int
ipi_handler(void *arg)
{
@@ -364,6 +463,7 @@ ipi_handler(void *arg)
return (FILTER_HANDLED);
}
+#endif
struct cpu_group *
cpu_topo(void)
@@ -490,3 +590,149 @@ cpu_mp_setmaxid(void)
mp_ncpus = 1;
mp_maxid = 0;
}
+
+#ifdef INTRNG
+/*
+ * Lookup IPI source.
+ */
+static struct intr_ipi *
+intr_ipi_lookup(u_int ipi)
+{
+
+ if (ipi >= INTR_IPI_COUNT)
+ panic("%s: no such IPI %u", __func__, ipi);
+
+ return (&ipi_sources[ipi]);
+}
+
+/*
+ * interrupt controller dispatch function for IPIs. It should
+ * be called straight from the interrupt controller, when associated
+ * interrupt source is learned. Or from anybody who has an interrupt
+ * source mapped.
+ */
+void
+intr_ipi_dispatch(u_int ipi, struct trapframe *tf)
+{
+ void *arg;
+ struct intr_ipi *ii;
+
+ ii = intr_ipi_lookup(ipi);
+ if (ii->ii_count == NULL)
+ panic("%s: not setup IPI %u", __func__, ipi);
+
+ intr_ipi_increment_count(ii->ii_count, PCPU_GET(cpuid));
+
+ /*
+ * Supply ipi filter with trapframe argument
+ * if none is registered.
+ */
+ arg = ii->ii_handler_arg != NULL ? ii->ii_handler_arg : tf;
+ ii->ii_handler(arg);
+}
+
+#ifdef notyet
+/*
+ * Map IPI into interrupt controller.
+ *
+ * Not SMP coherent.
+ */
+static int
+ipi_map(struct intr_irqsrc *isrc, u_int ipi)
+{
+ boolean_t is_percpu;
+ int error;
+
+ if (ipi >= INTR_IPI_COUNT)
+ panic("%s: no such IPI %u", __func__, ipi);
+
+ KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+
+ isrc->isrc_type = INTR_ISRCT_NAMESPACE;
+ isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
+ isrc->isrc_nspc_num = ipi_next_num;
+
+ error = PIC_REGISTER(intr_irq_root_dev, isrc, &is_percpu);
+ if (error == 0) {
+ isrc->isrc_dev = intr_irq_root_dev;
+ ipi_next_num++;
+ }
+ return (error);
+}
+
+/*
+ * Setup IPI handler to interrupt source.
+ *
+ * Note that there could be more ways how to send and receive IPIs
+ * on a platform like fast interrupts for example. In that case,
+ * one can call this function with ASIF_NOALLOC flag set and then
+ * call intr_ipi_dispatch() when appropriate.
+ *
+ * Not SMP coherent.
+ */
+int
+intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
+ void *arg, u_int flags)
+{
+ struct intr_irqsrc *isrc;
+ int error;
+
+ if (filter == NULL)
+ return(EINVAL);
+
+ isrc = intr_ipi_lookup(ipi);
+ if (isrc->isrc_ipifilter != NULL)
+ return (EEXIST);
+
+ if ((flags & AISHF_NOALLOC) == 0) {
+ error = ipi_map(isrc, ipi);
+ if (error != 0)
+ return (error);
+ }
+
+ isrc->isrc_ipifilter = filter;
+ isrc->isrc_arg = arg;
+ isrc->isrc_handlers = 1;
+ isrc->isrc_count = intr_ipi_setup_counters(name);
+ isrc->isrc_index = 0; /* it should not be used in IPI case */
+
+ if (isrc->isrc_dev != NULL) {
+ PIC_ENABLE_INTR(isrc->isrc_dev, isrc);
+ PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc);
+ }
+ return (0);
+}
+#endif
+
+/* Sending IPI */
+void
+ipi_all_but_self(u_int ipi)
+{
+ cpuset_t cpus;
+
+ cpus = all_cpus;
+ CPU_CLR(PCPU_GET(cpuid), &cpus);
+ CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+ intr_ipi_send(cpus, ipi);
+}
+
+void
+ipi_cpu(int cpu, u_int ipi)
+{
+ cpuset_t cpus;
+
+ CPU_ZERO(&cpus);
+ CPU_SET(cpu, &cpus);
+
+ CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
+ intr_ipi_send(cpus, ipi);
+}
+
+void
+ipi_selected(cpuset_t cpus, u_int ipi)
+{
+
+ CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+ intr_ipi_send(cpus, ipi);
+}
+#endif /* INTRNG */