Handle processor private interrupts better and add support for the PMU
interrupt. Thanks to jmcneill for review and suggestions.
This commit is contained in:
parent
6d3a7524b0
commit
b14a651935
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: bcm2835_intr.c,v 1.18 2019/03/01 08:05:46 skrll Exp $ */
|
||||
/* $NetBSD: bcm2835_intr.c,v 1.19 2019/03/01 14:53:12 skrll Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2012, 2015 The NetBSD Foundation, Inc.
|
||||
@ -30,7 +30,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.18 2019/03/01 08:05:46 skrll Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.19 2019/03/01 14:53:12 skrll Exp $");
|
||||
|
||||
#define _INTR_PRIVATE
|
||||
|
||||
@ -40,6 +40,8 @@ __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.18 2019/03/01 08:05:46 skrll Exp
|
||||
#include <sys/bus.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/kmem.h>
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <dev/fdt/fdtvar.h>
|
||||
@ -146,6 +148,20 @@ static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
|
||||
.intrstr = bcm2836mp_icu_fdt_intrstr
|
||||
};
|
||||
|
||||
struct bcm2836mp_interrupt {
|
||||
bool bi_done;
|
||||
TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
|
||||
int bi_irq;
|
||||
int bi_ipl;
|
||||
int bi_flags;
|
||||
int (*bi_func)(void *);
|
||||
void *bi_arg;
|
||||
void *bi_ihs[BCM2836_NCPUS];
|
||||
};
|
||||
|
||||
static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
|
||||
TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
|
||||
|
||||
struct bcm2835icu_softc {
|
||||
device_t sc_dev;
|
||||
bus_space_tag_t sc_iot;
|
||||
@ -450,20 +466,19 @@ bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen
|
||||
}
|
||||
|
||||
#define BCM2836MP_TIMER_IRQS __BITS(3,0)
|
||||
#define BCM2836MP_MAILBOX_IRQS __BITS(4,4)
|
||||
|
||||
#define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS)
|
||||
#define BCM2836MP_MAILBOX_IRQS __BITS(4,7)
|
||||
#define BCM2836MP_GPU_IRQ __BIT(8)
|
||||
#define BCM2836MP_PMU_IRQ __BIT(9)
|
||||
#define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
|
||||
|
||||
static void
|
||||
bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
|
||||
uint32_t irq_mask)
|
||||
{
|
||||
struct cpu_info * const ci = curcpu();
|
||||
const cpuid_t cpuid = ci->ci_core_id;
|
||||
const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
|
||||
const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
|
||||
const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
|
||||
|
||||
KASSERT(pic == &bcm2836mp_pic[cpuid]);
|
||||
KASSERT(irqbase == 0);
|
||||
|
||||
if (irq_mask & BCM2836MP_TIMER_IRQS) {
|
||||
@ -492,6 +507,12 @@ bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
|
||||
BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
|
||||
BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
|
||||
}
|
||||
if (irq_mask & BCM2836MP_PMU_IRQ) {
|
||||
bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
|
||||
__BIT(cpuid));
|
||||
bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
|
||||
BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@ -500,12 +521,10 @@ static void
|
||||
bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
|
||||
uint32_t irq_mask)
|
||||
{
|
||||
struct cpu_info * const ci = curcpu();
|
||||
const cpuid_t cpuid = ci->ci_core_id;
|
||||
const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
|
||||
const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
|
||||
const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
|
||||
|
||||
KASSERT(pic == &bcm2836mp_pic[cpuid]);
|
||||
KASSERT(irqbase == 0);
|
||||
|
||||
if (irq_mask & BCM2836MP_TIMER_IRQS) {
|
||||
@ -526,6 +545,10 @@ bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
|
||||
BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
|
||||
val);
|
||||
}
|
||||
if (irq_mask & BCM2836MP_PMU_IRQ) {
|
||||
bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
|
||||
__BIT(cpuid));
|
||||
}
|
||||
|
||||
bcm2835_barrier();
|
||||
return;
|
||||
@ -656,14 +679,18 @@ bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
|
||||
#if defined(MULTIPROCESSOR)
|
||||
intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
|
||||
IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
|
||||
#endif
|
||||
/* clock interrupt will attach with gtmr */
|
||||
if (cpuid == 0)
|
||||
return;
|
||||
#if defined(SOC_BCM2836)
|
||||
intr_establish(BCM2836_INT_CNTVIRQ_CPUN(cpuid), IPL_CLOCK,
|
||||
IST_LEVEL | IST_MPSAFE, gtmr_intr, NULL);
|
||||
|
||||
struct bcm2836mp_interrupt *bip;
|
||||
TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
|
||||
if (bip->bi_done)
|
||||
continue;
|
||||
|
||||
const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
|
||||
void *ih = intr_establish(irq, bip->bi_ipl,
|
||||
IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
|
||||
|
||||
bip->bi_ihs[cpuid] = ih;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -672,7 +699,7 @@ bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
|
||||
{
|
||||
if (!specifier)
|
||||
return -1;
|
||||
return be32toh(specifier[0]) + BCM2836_INT_LOCALBASE;
|
||||
return be32toh(specifier[0]);
|
||||
}
|
||||
|
||||
static void *
|
||||
@ -680,19 +707,95 @@ bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
|
||||
int (*func)(void *), void *arg)
|
||||
{
|
||||
int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
|
||||
int irq;
|
||||
struct bcm2836mp_interrupt *bip;
|
||||
void *ih;
|
||||
|
||||
irq = bcm2836mp_icu_fdt_decode_irq(specifier);
|
||||
int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
|
||||
if (irq == -1)
|
||||
return NULL;
|
||||
|
||||
return intr_establish(irq, ipl, IST_LEVEL | iflags, func, arg);
|
||||
TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
|
||||
if (irq == bip->bi_irq)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
|
||||
if (bip == NULL)
|
||||
return NULL;
|
||||
|
||||
bip->bi_done = false;
|
||||
bip->bi_irq = irq;
|
||||
bip->bi_ipl = ipl;
|
||||
bip->bi_flags = IST_LEVEL | iflags;
|
||||
bip->bi_func = func;
|
||||
bip->bi_arg = arg;
|
||||
|
||||
/*
|
||||
* If we're not cold and the BPs have been started then we can register the
|
||||
* interupt for all CPUs now, e.g. PMU
|
||||
*/
|
||||
if (!cold) {
|
||||
for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
|
||||
ih = intr_establish(BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
|
||||
IST_LEVEL | iflags, func, arg);
|
||||
if (!ih) {
|
||||
kmem_free(bip, sizeof(*bip));
|
||||
return NULL;
|
||||
}
|
||||
bip->bi_ihs[cpuid] = ih;
|
||||
|
||||
}
|
||||
bip->bi_done = true;
|
||||
ih = bip->bi_ihs[0];
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we can only establish the interrupt for the BP and
|
||||
* delay until bcm2836mp_intr_init is called for each AP, e.g.
|
||||
* gtmr
|
||||
*/
|
||||
ih = intr_establish(BCM2836_INT_BASECPUN(0) + irq, ipl,
|
||||
IST_LEVEL | iflags, func, arg);
|
||||
if (!ih) {
|
||||
kmem_free(bip, sizeof(*bip));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bip->bi_ihs[0] = ih;
|
||||
for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
|
||||
bip->bi_ihs[cpuid] = NULL;
|
||||
|
||||
done:
|
||||
TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
|
||||
|
||||
/*
|
||||
* Return the intr_establish handle for cpu 0 for API compatibility.
|
||||
* Any cpu would do here as these sources don't support set_affinity
|
||||
* when the handle is used in interrupt_distribute(9)
|
||||
*/
|
||||
return ih;
|
||||
}
|
||||
|
||||
static void
|
||||
bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
|
||||
{
|
||||
intr_disestablish(ih);
|
||||
struct bcm2836mp_interrupt *bip;
|
||||
|
||||
TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
|
||||
if (bip->bi_ihs[0] == ih)
|
||||
break;
|
||||
}
|
||||
|
||||
if (bip == NULL)
|
||||
return;
|
||||
|
||||
for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
|
||||
intr_disestablish(bip->bi_ihs[cpuid]);
|
||||
|
||||
TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
|
||||
|
||||
kmem_free(bip, sizeof(*bip));
|
||||
}
|
||||
|
||||
static bool
|
||||
|
Loading…
Reference in New Issue
Block a user