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
This commit is contained in:
Andrew Turner 2016-05-16 10:48:51 +00:00
parent 4e1763d34c
commit 72b3f638b7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=299936
6 changed files with 311 additions and 9 deletions

View File

@ -80,7 +80,13 @@ configure(void *dummy)
static void
configure_final(void *dummy)
{
#ifdef INTRNG
/* Enable interrupt reception on this CPU */
intr_enable();
#else
arm_enable_intr();
#endif
cninit_finish();
if (bootverbose)

View File

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

View File

@ -271,7 +271,13 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
enum intr_polarity pol)
{
#ifdef INTRNG
/* TODO: This is wrong, it's needed for ACPI */
device_printf(dev, "bus_config_intr is obsolete and not supported!\n");
return (EOPNOTSUPP);
#else
return (intr_irq_config(irq, trig, pol));
#endif
}
static int
@ -288,8 +294,12 @@ nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
if (error)
return (error);
#ifdef INTRNG
error = intr_setup_irq(child, res, filt, intr, arg, flags, cookiep);
#else
error = arm_setup_intr(device_get_nameunit(child), filt, intr,
arg, rman_get_start(res), flags, cookiep);
#endif
return (error);
}
@ -298,7 +308,11 @@ static int
nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
{
#ifdef INTRNG
return (intr_teardown_irq(child, r, ih));
#else
return (intr_irq_remove_handler(child, rman_get_start(r), ih));
#endif
}
#ifdef SMP
@ -306,7 +320,11 @@ static int
nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu)
{
#ifdef INTRNG
return (intr_bind_irq(child, irq, cpu));
#else
return (intr_irq_bind(rman_get_start(irq), cpu));
#endif
}
#endif
@ -429,6 +447,9 @@ static int
nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
pcell_t *intr)
{
#ifdef INTRNG
return (intr_fdt_map_irq(iparent, intr, icells));
#else
int irq;
if (icells == 3) {
@ -441,6 +462,7 @@ nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
irq = intr[0];
return (irq);
#endif
}
#endif

View File

@ -29,6 +29,28 @@
#ifndef _MACHINE_INTR_H_
#define _MACHINE_INTR_H_
#ifdef INTRNG
#ifdef FDT
#include <dev/ofw/openfirm.h>
#endif
#include <sys/intr.h>
#ifndef NIRQ
#define NIRQ 1024 /* XXX - It should be an option. */
#endif
static inline void
arm_irq_memory_barrier(uintptr_t irq)
{
}
#ifdef SMP
void intr_ipi_dispatch(u_int, struct trapframe *);
#endif
#else
int intr_irq_config(u_int, enum intr_trigger, enum intr_polarity);
void intr_irq_handler(struct trapframe *);
int intr_irq_remove_handler(device_t, u_int, void *);
@ -55,5 +77,6 @@ void arm_init_secondary(void);
void arm_setup_ipihandler(driver_filter_t *, u_int);
void arm_unmask_ipi(u_int);
#endif
#endif
#endif /* _MACHINE_INTR_H */

View File

@ -1,5 +1,6 @@
# $FreeBSD$
arm/arm/generic_timer.c standard
arm/arm/gic.c optional intrng
arm/arm/pmu.c standard
arm64/acpica/acpi_machdep.c optional acpi
arm64/acpica/OsdEnvironment.c optional acpi
@ -24,14 +25,14 @@ arm64/arm64/disassem.c optional ddb
arm64/arm64/dump_machdep.c standard
arm64/arm64/elf_machdep.c standard
arm64/arm64/exception.S standard
arm64/arm64/gic.c standard
arm64/arm64/gic_acpi.c optional acpi
arm64/arm64/gic_fdt.c optional fdt
arm64/arm64/gic_v3.c standard
arm64/arm64/gic_v3_fdt.c optional fdt
arm64/arm64/gic_v3_its.c standard
arm64/arm64/gic.c optional !intrng
arm64/arm64/gic_acpi.c optional !intrng acpi
arm64/arm64/gic_fdt.c optional !intrng fdt
arm64/arm64/gic_v3.c optional !intrng
arm64/arm64/gic_v3_fdt.c optional !intrng fdt
arm64/arm64/gic_v3_its.c optional !intrng
arm64/arm64/identcpu.c standard
arm64/arm64/intr_machdep.c standard
arm64/arm64/intr_machdep.c optional !intrng
arm64/arm64/in_cksum.c optional inet | inet6
arm64/arm64/locore.S standard no-obj
arm64/arm64/machdep.c standard
@ -40,7 +41,7 @@ arm64/arm64/minidump_machdep.c standard
arm64/arm64/mp_machdep.c optional smp
arm64/arm64/nexus.c standard
arm64/arm64/ofw_machdep.c optional fdt
arm64/arm64/pic_if.m standard
arm64/arm64/pic_if.m optional !intrng
arm64/arm64/pmap.c standard
arm64/arm64/stack_machdep.c optional ddb | stack
arm64/arm64/support.S standard
@ -83,7 +84,10 @@ dev/vnic/thunder_mdio_fdt.c optional vnic fdt
dev/vnic/thunder_mdio.c optional vnic
dev/vnic/lmac_if.m optional vnic
kern/kern_clocksource.c standard
kern/msi_if.m optional intrng
kern/pic_if.m optional intrng
kern/subr_devmap.c standard
kern/subr_intr.c optional intrng
libkern/bcmp.c standard
libkern/ffs.c standard
libkern/ffsl.c standard

View File

@ -1,6 +1,7 @@
# $FreeBSD$
ARM64 opt_global.h
INTRNG opt_global.h
SOCDEV_PA opt_global.h
SOCDEV_VA opt_global.h
THUNDERX_PASS_1_1_ERRATA opt_global.h