svn commit: r297230 - in head/sys: arm/arm arm/include kern sys

Svatopluk Kraus skra at FreeBSD.org
Thu Mar 24 09:55:12 UTC 2016


Author: skra
Date: Thu Mar 24 09:55:11 2016
New Revision: 297230
URL: https://svnweb.freebsd.org/changeset/base/297230

Log:
  Generalize IPI support for ARM intrng and use it for interrupt
  controller IPI provider.
  
  New struct intr_ipi is defined which keeps all info about an IPI:
  its name, counter, send and dispatch methods. Generic intr_ipi_setup(),
  intr_ipi_send() and intr_ipi_dispatch() functions are implemented.
  
  An IPI provider must implement two functions:
  (1) an intr_ipi_send_t function which is able to send an IPI,
  (2) a setup function which initializes itself for an IPI and
      calls intr_ipi_setup() with appropriate arguments.
  
  Differential Revision:	https://reviews.freebsd.org/D5700

Modified:
  head/sys/arm/arm/gic.c
  head/sys/arm/arm/machdep_intr.c
  head/sys/arm/arm/mp_machdep.c
  head/sys/arm/include/intr.h
  head/sys/arm/include/smp.h
  head/sys/kern/pic_if.m
  head/sys/kern/subr_intr.c
  head/sys/sys/intr.h

Modified: head/sys/arm/arm/gic.c
==============================================================================
--- head/sys/arm/arm/gic.c	Thu Mar 24 09:35:29 2016	(r297229)
+++ head/sys/arm/arm/gic.c	Thu Mar 24 09:55:11 2016	(r297230)
@@ -121,6 +121,11 @@ __FBSDID("$FreeBSD$");
 static u_int gic_irq_cpu;
 static int arm_gic_intr(void *);
 static int arm_gic_bind(device_t dev, struct intr_irqsrc *isrc);
+
+#ifdef SMP
+u_int sgi_to_ipi[GIC_LAST_SGI - GIC_FIRST_SGI + 1];
+#define	ISRC_IPI(isrc)	sgi_to_ipi[isrc->isrc_data - GIC_FIRST_SGI]
+#endif
 #endif
 
 struct arm_gic_softc {
@@ -562,7 +567,7 @@ dispatch_irq:
 #ifdef SMP
 		/* Call EOI for all IPI before dispatch. */
 		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
-		intr_ipi_dispatch(isrc, tf);
+		intr_ipi_dispatch(ISRC_IPI(isrc), tf);
 		goto next_irq;
 #else
 		device_printf(sc->gic_dev, "SGI %u on UP system detected\n",
@@ -918,6 +923,20 @@ arm_gic_ipi_send(device_t dev, struct in
 
 	gic_d_write_4(sc, GICD_SGIR(0), val | irq);
 }
+
+static int
+arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc *isrc)
+{
+	struct arm_gic_softc *sc = device_get_softc(dev);
+	u_int irq;
+	int error;
+
+	error = gic_map_nspc(sc, isrc, &irq);
+	if (error != 0)
+		return (error);
+	sgi_to_ipi[irq - GIC_FIRST_SGI] = ipi;
+	return (0);
+}
 #endif
 #else
 static int
@@ -1146,6 +1165,7 @@ static device_method_t arm_gic_methods[]
 	DEVMETHOD(pic_bind,		arm_gic_bind),
 	DEVMETHOD(pic_init_secondary,	arm_gic_init_secondary),
 	DEVMETHOD(pic_ipi_send,		arm_gic_ipi_send),
+	DEVMETHOD(pic_ipi_setup,	arm_gic_ipi_setup),
 #endif
 #endif
 	{ 0, 0 }

Modified: head/sys/arm/arm/machdep_intr.c
==============================================================================
--- head/sys/arm/arm/machdep_intr.c	Thu Mar 24 09:35:29 2016	(r297229)
+++ head/sys/arm/arm/machdep_intr.c	Thu Mar 24 09:55:11 2016	(r297230)
@@ -64,8 +64,19 @@ __FBSDID("$FreeBSD$");
 #include "pic_if.h"
 
 #ifdef SMP
-static struct intr_irqsrc ipi_sources[INTR_IPI_COUNT];
-static u_int ipi_next_num;
+#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];
+u_int ipi_next_num;
 #endif
 #endif
 
@@ -134,10 +145,7 @@ arm_irq_memory_barrier(uintptr_t irq)
 
 #ifdef ARM_INTRNG
 #ifdef SMP
-/*
- *  Lookup IPI source.
- */
-static struct intr_irqsrc *
+static inline struct intr_ipi *
 intr_ipi_lookup(u_int ipi)
 {
 
@@ -147,112 +155,97 @@ intr_ipi_lookup(u_int 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(struct intr_irqsrc *isrc, struct trapframe *tf)
+intr_ipi_dispatch(u_int ipi, struct trapframe *tf)
 {
 	void *arg;
+	struct intr_ipi *ii;
 
-	KASSERT(isrc != NULL, ("%s: no source", __func__));
+	ii = intr_ipi_lookup(ipi);
+	if (ii->ii_count == NULL)
+		panic("%s: not setup IPI %u", __func__, ipi);
 
-	intr_ipi_increment_count(isrc->isrc_count, PCPU_GET(cpuid));
+	intr_ipi_increment_count(ii->ii_count, PCPU_GET(cpuid));
 
 	/*
 	 * Supply ipi filter with trapframe argument
 	 * if none is registered.
 	 */
-	arg = isrc->isrc_arg != NULL ? isrc->isrc_arg : tf;
-	isrc->isrc_ipifilter(arg);
+	arg = ii->ii_handler_arg != NULL ? ii->ii_handler_arg : tf;
+	ii->ii_handler(arg);
 }
 
-/*
- *  Map IPI into interrupt controller.
- *
- *  Not SMP coherent.
- */
-static int
-ipi_map(struct intr_irqsrc *isrc, u_int ipi)
+void
+intr_ipi_send(cpuset_t cpus, u_int ipi)
 {
-	boolean_t is_percpu;
-	int error;
+	struct intr_ipi *ii;
 
-	if (ipi >= INTR_IPI_COUNT)
-		panic("%s: no such IPI %u", __func__, ipi);
+	ii = intr_ipi_lookup(ipi);
+	if (ii->ii_count == NULL)
+		panic("%s: not setup IPI %u", __func__, ipi);
 
-	KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+	ii->ii_send(ii->ii_send_arg, cpus);
+}
 
-	isrc->isrc_type = INTR_ISRCT_NAMESPACE;
-	isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
-	isrc->isrc_nspc_num = ipi_next_num;
+void
+intr_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
+    void *h_arg, intr_ipi_send_t *send, void *s_arg)
+{
+	struct intr_ipi *ii;
+
+	ii = intr_ipi_lookup(ipi);
 
-	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);
+	KASSERT(hand != NULL, ("%s: ipi %u no handler", __func__, ipi));
+	KASSERT(send != NULL, ("%s: ipi %u no sender", __func__, ipi));
+	KASSERT(ii->ii_count == NULL, ("%s: ipi %u reused", __func__, ipi));
+
+	ii->ii_handler = hand;
+	ii->ii_handler_arg = h_arg;
+	ii->ii_send = send;
+	ii->ii_send_arg = s_arg;
+	strlcpy(ii->ii_name, name, INTR_IPI_NAMELEN);
+	ii->ii_count = intr_ipi_setup_counters(name);
 }
 
 /*
- *  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.
+ *  Send IPI thru interrupt controller.
  */
-int
-intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
-    void *arg, u_int flags)
+static void
+pic_ipi_send(void *arg, cpuset_t cpus)
 {
-	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);
+	KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
+	PIC_IPI_SEND(intr_irq_root_dev, arg, cpus);
 }
 
 /*
- *  Send IPI thru interrupt controller.
+ *  Setup IPI handler on interrupt controller.
+ *
+ *  Not SMP coherent.
  */
-void
-pic_ipi_send(cpuset_t cpus, u_int ipi)
+int
+intr_pic_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
+    void *arg)
 {
+	int error;
 	struct intr_irqsrc *isrc;
 
-	isrc = intr_ipi_lookup(ipi);
-
 	KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
-	PIC_IPI_SEND(intr_irq_root_dev, isrc, cpus);
+
+	isrc = intr_isrc_alloc(INTR_ISRCT_NAMESPACE, 0);
+	isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI;
+	isrc->isrc_nspc_num = ipi_next_num;
+
+	error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, isrc);
+	if (error != 0)
+		return (error);
+
+	ipi_next_num++;
+
+	isrc->isrc_dev = intr_irq_root_dev;
+	isrc->isrc_handlers = 1;
+	intr_ipi_setup(ipi, name, hand, arg, pic_ipi_send, isrc);
+	return (0);
 }
 #endif
 #endif

Modified: head/sys/arm/arm/mp_machdep.c
==============================================================================
--- head/sys/arm/arm/mp_machdep.c	Thu Mar 24 09:35:29 2016	(r297229)
+++ head/sys/arm/arm/mp_machdep.c	Thu Mar 24 09:55:11 2016	(r297230)
@@ -429,12 +429,11 @@ release_aps(void *dummy __unused)
 		return;
 
 #ifdef ARM_INTRNG
-	intr_ipi_set_handler(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL, 0);
-	intr_ipi_set_handler(IPI_AST, "ast", ipi_ast, NULL, 0);
-	intr_ipi_set_handler(IPI_STOP, "stop", ipi_stop, NULL, 0);
-	intr_ipi_set_handler(IPI_PREEMPT, "preempt", ipi_preempt, NULL, 0);
-	intr_ipi_set_handler(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL, 0);
-
+	intr_pic_ipi_setup(IPI_RENDEZVOUS, "rendezvous", ipi_rendezvous, NULL);
+	intr_pic_ipi_setup(IPI_AST, "ast", ipi_ast, NULL);
+	intr_pic_ipi_setup(IPI_STOP, "stop", ipi_stop, NULL);
+	intr_pic_ipi_setup(IPI_PREEMPT, "preempt", ipi_preempt, NULL);
+	intr_pic_ipi_setup(IPI_HARDCLOCK, "hardclock", ipi_hardclock, NULL);
 #else
 #ifdef IPI_IRQ_START
 	start = IPI_IRQ_START;
@@ -502,7 +501,11 @@ ipi_all_but_self(u_int ipi)
 	other_cpus = all_cpus;
 	CPU_CLR(PCPU_GET(cpuid), &other_cpus);
 	CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+#ifdef ARM_INTRNG
+	intr_ipi_send(other_cpus, ipi);
+#else
 	pic_ipi_send(other_cpus, ipi);
+#endif
 }
 
 void
@@ -514,7 +517,11 @@ ipi_cpu(int cpu, u_int ipi)
 	CPU_SET(cpu, &cpus);
 
 	CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x", __func__, cpu, ipi);
+#ifdef ARM_INTRNG
+	intr_ipi_send(cpus, ipi);
+#else
 	pic_ipi_send(cpus, ipi);
+#endif
 }
 
 void
@@ -522,6 +529,9 @@ ipi_selected(cpuset_t cpus, u_int ipi)
 {
 
 	CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
+#ifdef ARM_INTRNG
+	intr_ipi_send(cpus, ipi);
+#else
 	pic_ipi_send(cpus, ipi);
+#endif
 }
-

Modified: head/sys/arm/include/intr.h
==============================================================================
--- head/sys/arm/include/intr.h	Thu Mar 24 09:35:29 2016	(r297229)
+++ head/sys/arm/include/intr.h	Thu Mar 24 09:55:11 2016	(r297230)
@@ -52,14 +52,17 @@
 #include <sys/intr.h>
 
 #ifdef SMP
-void intr_ipi_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf);
+typedef void intr_ipi_send_t(void *, cpuset_t);
+typedef void intr_ipi_handler_t(void *);
 
-#define AISHF_NOALLOC	0x0001
+void intr_ipi_dispatch(u_int, struct trapframe *);
+void intr_ipi_send(cpuset_t, u_int);
 
-int intr_ipi_set_handler(u_int ipi, const char *name, intr_ipi_filter_t *filter,
-    void *arg, u_int flags);
-#endif
+void intr_ipi_setup(u_int, const char *, intr_ipi_handler_t *, void *,
+    intr_ipi_send_t *, void *);
 
+int intr_pic_ipi_setup(u_int, const char *, intr_ipi_handler_t *, void *);
+#endif
 #else /* ARM_INTRNG */
 
 /* XXX move to std.* files? */

Modified: head/sys/arm/include/smp.h
==============================================================================
--- head/sys/arm/include/smp.h	Thu Mar 24 09:35:29 2016	(r297229)
+++ head/sys/arm/include/smp.h	Thu Mar 24 09:55:11 2016	(r297230)
@@ -37,8 +37,8 @@ void	ipi_cpu(int cpu, u_int ipi);
 void	ipi_selected(cpuset_t cpus, u_int ipi);
 
 /* PIC interface */
-void	pic_ipi_send(cpuset_t cpus, u_int ipi);
 #ifndef ARM_INTRNG
+void	pic_ipi_send(cpuset_t cpus, u_int ipi);
 void	pic_ipi_clear(int ipi);
 int	pic_ipi_read(int arg);
 #endif

Modified: head/sys/kern/pic_if.m
==============================================================================
--- head/sys/kern/pic_if.m	Thu Mar 24 09:35:29 2016	(r297229)
+++ head/sys/kern/pic_if.m	Thu Mar 24 09:55:11 2016	(r297230)
@@ -60,6 +60,13 @@ CODE {
 	{
 		return;
 	}
+
+	static int
+	dflt_pic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc *isrc)
+	{
+
+		return (EOPNOTSUPP);
+	}
 };
 
 METHOD int register {
@@ -122,3 +129,9 @@ METHOD void ipi_send {
 	struct intr_irqsrc	*isrc;
 	cpuset_t		cpus;
 } DEFAULT null_pic_ipi_send;
+
+METHOD int ipi_setup {
+	device_t		dev;
+	u_int			ipi;
+	struct intr_irqsrc	*isrc;
+} DEFAULT dflt_pic_ipi_setup;

Modified: head/sys/kern/subr_intr.c
==============================================================================
--- head/sys/kern/subr_intr.c	Thu Mar 24 09:35:29 2016	(r297229)
+++ head/sys/kern/subr_intr.c	Thu Mar 24 09:55:11 2016	(r297230)
@@ -311,8 +311,8 @@ intr_irq_dispatch(struct intr_irqsrc *is
 /*
  *  Allocate interrupt source.
  */
-static struct intr_irqsrc *
-isrc_alloc(u_int type, u_int extsize)
+struct intr_irqsrc *
+intr_isrc_alloc(u_int type, u_int extsize)
 {
 	struct intr_irqsrc *isrc;
 
@@ -329,8 +329,8 @@ isrc_alloc(u_int type, u_int extsize)
 /*
  *  Free interrupt source.
  */
-static void
-isrc_free(struct intr_irqsrc *isrc)
+void
+intr_isrc_free(struct intr_irqsrc *isrc)
 {
 
 	free(isrc, M_INTRNG);
@@ -462,20 +462,20 @@ intr_namespace_map_irq(device_t dev, uin
 	struct intr_irqsrc *isrc, *new_isrc;
 	int error;
 
-	new_isrc = isrc_alloc(INTR_ISRCT_NAMESPACE, 0);
+	new_isrc = intr_isrc_alloc(INTR_ISRCT_NAMESPACE, 0);
 
 	mtx_lock(&isrc_table_lock);
 	isrc = isrc_namespace_lookup(dev, type, num);
 	if (isrc != NULL) {
 		mtx_unlock(&isrc_table_lock);
-		isrc_free(new_isrc);
+		intr_isrc_free(new_isrc);
 		return (isrc->isrc_irq);	/* already mapped */
 	}
 
 	error = isrc_alloc_irq_locked(new_isrc);
 	if (error != 0) {
 		mtx_unlock(&isrc_table_lock);
-		isrc_free(new_isrc);
+		intr_isrc_free(new_isrc);
 		return (IRQ_INVALID);		/* no space left */
 	}
 
@@ -526,20 +526,20 @@ intr_fdt_map_irq(phandle_t node, pcell_t
 	xref = (intptr_t)node;	/* It's so simple for now. */
 
 	cellsize = ncells * sizeof(*cells);
-	new_isrc = isrc_alloc(INTR_ISRCT_FDT, cellsize);
+	new_isrc = intr_isrc_alloc(INTR_ISRCT_FDT, cellsize);
 
 	mtx_lock(&isrc_table_lock);
 	isrc = isrc_fdt_lookup(xref, cells, ncells);
 	if (isrc != NULL) {
 		mtx_unlock(&isrc_table_lock);
-		isrc_free(new_isrc);
+		intr_isrc_free(new_isrc);
 		return (isrc->isrc_irq);	/* already mapped */
 	}
 
 	error = isrc_alloc_irq_locked(new_isrc);
 	if (error != 0) {
 		mtx_unlock(&isrc_table_lock);
-		isrc_free(new_isrc);
+		intr_isrc_free(new_isrc);
 		return (IRQ_INVALID);		/* no space left */
 	}
 

Modified: head/sys/sys/intr.h
==============================================================================
--- head/sys/sys/intr.h	Thu Mar 24 09:35:29 2016	(r297229)
+++ head/sys/sys/intr.h	Thu Mar 24 09:55:11 2016	(r297230)
@@ -50,8 +50,6 @@ typedef int intr_irq_filter_t(void *arg)
 
 #define INTR_ISRC_NAMELEN	(MAXCOMLEN + 1)
 
-typedef void intr_ipi_filter_t(void *arg);
-
 enum intr_isrc_type {
 	INTR_ISRCT_NAMESPACE,
 	INTR_ISRCT_FDT
@@ -81,15 +79,17 @@ struct intr_irqsrc {
 	struct intr_event *	isrc_event;
 #ifdef INTR_SOLO
 	intr_irq_filter_t *	isrc_filter;
-#endif
-	intr_ipi_filter_t *	isrc_ipifilter;
 	void *			isrc_arg;
+#endif
 #ifdef FDT
 	u_int			isrc_ncells;
 	pcell_t			isrc_cells[];	/* leave it last */
 #endif
 };
 
+struct intr_irqsrc *intr_isrc_alloc(u_int type, u_int extsize);
+void intr_isrc_free(struct intr_irqsrc *isrc);
+
 void intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...)
     __printflike(2, 3);
 


More information about the svn-src-head mailing list