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
This commit is contained in:
Svatopluk Kraus 2016-03-24 09:55:11 +00:00
parent 6227e59635
commit 61c8fde5d6
8 changed files with 150 additions and 111 deletions

View File

@ -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 intr_irqsrc *isrc, cpuset_t cpus)
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 }

View File

@ -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__));
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);
ii->ii_send(ii->ii_send_arg, cpus);
}
/*
* 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)
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_irqsrc *isrc;
int error;
struct intr_ipi *ii;
if (filter == NULL)
return(EINVAL);
ii = intr_ipi_lookup(ipi);
isrc = intr_ipi_lookup(ipi);
if (isrc->isrc_ipifilter != NULL)
return (EEXIST);
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));
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);
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);
}
/*
* Send IPI thru interrupt controller.
*/
void
pic_ipi_send(cpuset_t cpus, u_int ipi)
static void
pic_ipi_send(void *arg, cpuset_t cpus)
{
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);
PIC_IPI_SEND(intr_irq_root_dev, arg, cpus);
}
/*
* Setup IPI handler on interrupt controller.
*
* Not SMP coherent.
*/
int
intr_pic_ipi_setup(u_int ipi, const char *name, intr_ipi_handler_t *hand,
void *arg)
{
int error;
struct intr_irqsrc *isrc;
KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__));
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

View File

@ -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
}

View File

@ -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);
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? */

View File

@ -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

View File

@ -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;

View File

@ -311,8 +311,8 @@ intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf)
/*
* 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, uint16_t type, uint16_t num)
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 *cells, u_int ncells)
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 */
}

View File

@ -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);