-/* $OpenBSD: cpu.c,v 1.64 2022/07/12 03:55:34 jsg Exp $ */
+/* $OpenBSD: cpu.c,v 1.65 2022/07/13 09:28:18 kettenis Exp $ */
/*
* Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
#include <sys/device.h>
#include <sys/sysctl.h>
#include <sys/task.h>
+#include <sys/user.h>
#include <uvm/uvm.h>
#endif
}
-int cpu_hatch_secondary(struct cpu_info *ci, int, uint64_t);
+void cpu_init(void);
+int cpu_start_secondary(struct cpu_info *ci, int, uint64_t);
int cpu_clockspeed(int *);
int
{
struct fdt_attach_args *faa = aux;
struct cpu_info *ci;
+ void *kstack;
#ifdef MULTIPROCESSOR
uint64_t mpidr = READ_SPECIALREG(mpidr_el1);
#endif
- uint64_t id_aa64mmfr1, sctlr;
uint32_t opp;
KASSERT(faa->fa_nreg > 0);
printf(" mpidr %llx:", ci->ci_mpidr);
+ kstack = km_alloc(USPACE, &kv_any, &kp_zero, &kd_waitok);
+ ci->ci_el1_stkend = (vaddr_t)kstack + USPACE - 16;
+
#ifdef MULTIPROCESSOR
if (ci->ci_flags & CPUF_AP) {
char buf[32];
}
sched_init_cpu(ci);
- if (cpu_hatch_secondary(ci, spinup_method, spinup_data)) {
+ if (cpu_start_secondary(ci, spinup_method, spinup_data)) {
atomic_setbits_int(&ci->ci_flags, CPUF_IDENTIFY);
__asm volatile("dsb sy; sev" ::: "memory");
cpu_cpuspeed = cpu_clockspeed;
}
- /* Enable PAN. */
- id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
- if (ID_AA64MMFR1_PAN(id_aa64mmfr1) >= ID_AA64MMFR1_PAN_IMPL) {
- sctlr = READ_SPECIALREG(sctlr_el1);
- sctlr &= ~SCTLR_SPAN;
- WRITE_SPECIALREG(sctlr_el1, sctlr);
- }
-
- /* Initialize debug registers. */
- WRITE_SPECIALREG(mdscr_el1, DBG_MDSCR_TDCC);
- WRITE_SPECIALREG(oslar_el1, 0);
+ cpu_init();
#ifdef MULTIPROCESSOR
}
#endif
printf("\n");
}
+void
+cpu_init(void)
+{
+ uint64_t id_aa64mmfr1, sctlr;
+ uint64_t tcr;
+
+ WRITE_SPECIALREG(ttbr0_el1, pmap_kernel()->pm_pt0pa);
+ __asm volatile("isb");
+ tcr = READ_SPECIALREG(tcr_el1);
+ tcr &= ~TCR_T0SZ(0x3f);
+ tcr |= TCR_T0SZ(64 - USER_SPACE_BITS);
+ tcr |= TCR_A1;
+ WRITE_SPECIALREG(tcr_el1, tcr);
+ cpu_tlb_flush();
+
+ /* Enable PAN. */
+ id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
+ if (ID_AA64MMFR1_PAN(id_aa64mmfr1) >= ID_AA64MMFR1_PAN_IMPL) {
+ sctlr = READ_SPECIALREG(sctlr_el1);
+ sctlr &= ~SCTLR_SPAN;
+ WRITE_SPECIALREG(sctlr_el1, sctlr);
+ }
+
+ /* Initialize debug registers. */
+ WRITE_SPECIALREG(mdscr_el1, DBG_MDSCR_TDCC);
+ WRITE_SPECIALREG(oslar_el1, 0);
+}
+
void
cpu_flush_bp_noop(void)
{
#ifdef MULTIPROCESSOR
void cpu_boot_secondary(struct cpu_info *ci);
-void cpu_hatch(void);
+void cpu_hatch_secondary(void);
void
cpu_boot_secondary_processors(void)
}
void
-cpu_hatch_spin_table(struct cpu_info *ci, uint64_t start, uint64_t data)
+cpu_start_spin_table(struct cpu_info *ci, uint64_t start, uint64_t data)
{
/* this reuses the zero page for the core */
vaddr_t start_pg = zero_page + (PAGE_SIZE * ci->ci_cpuid);
}
int
-cpu_hatch_secondary(struct cpu_info *ci, int method, uint64_t data)
+cpu_start_secondary(struct cpu_info *ci, int method, uint64_t data)
{
extern uint64_t pmap_avail_kvo;
extern paddr_t cpu_hatch_ci;
paddr_t startaddr;
- void *kstack;
uint64_t ttbr1;
int rc = 0;
- kstack = km_alloc(USPACE, &kv_any, &kp_zero, &kd_waitok);
- ci->ci_el1_stkend = (vaddr_t)kstack + USPACE - 16;
-
pmap_extract(pmap_kernel(), (vaddr_t)ci, &cpu_hatch_ci);
__asm("mrs %x0, ttbr1_el1": "=r"(ttbr1));
cpu_dcache_wb_range((vaddr_t)&cpu_hatch_ci, sizeof(paddr_t));
cpu_dcache_wb_range((vaddr_t)ci, sizeof(*ci));
- startaddr = (vaddr_t)cpu_hatch + pmap_avail_kvo;
+ startaddr = (vaddr_t)cpu_hatch_secondary + pmap_avail_kvo;
switch (method) {
case 1:
break;
case 2:
/* spin-table */
- cpu_hatch_spin_table(ci, startaddr, data);
+ cpu_start_spin_table(ci, startaddr, data);
rc = 1;
break;
default:
}
void
-cpu_start_secondary(struct cpu_info *ci)
+cpu_init_secondary(struct cpu_info *ci)
{
- uint64_t id_aa64mmfr1, sctlr;
- uint64_t tcr;
int s;
ci->ci_flags |= CPUF_PRESENT;
__asm volatile("dsb sy" ::: "memory");
- while ((ci->ci_flags & CPUF_IDENTIFY) == 0)
- __asm volatile("wfe");
+ if ((ci->ci_flags & CPUF_IDENTIFIED) == 0) {
+ while ((ci->ci_flags & CPUF_IDENTIFY) == 0)
+ __asm volatile("wfe");
- cpu_identify(ci);
- atomic_setbits_int(&ci->ci_flags, CPUF_IDENTIFIED);
- __asm volatile("dsb sy" ::: "memory");
+ cpu_identify(ci);
+ atomic_setbits_int(&ci->ci_flags, CPUF_IDENTIFIED);
+ __asm volatile("dsb sy" ::: "memory");
+ }
while ((ci->ci_flags & CPUF_GO) == 0)
__asm volatile("wfe");
- WRITE_SPECIALREG(ttbr0_el1, pmap_kernel()->pm_pt0pa);
- __asm volatile("isb");
- tcr = READ_SPECIALREG(tcr_el1);
- tcr &= ~TCR_T0SZ(0x3f);
- tcr |= TCR_T0SZ(64 - USER_SPACE_BITS);
- tcr |= TCR_A1;
- WRITE_SPECIALREG(tcr_el1, tcr);
- cpu_tlb_flush();
-
- /* Enable PAN. */
- id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
- if (ID_AA64MMFR1_PAN(id_aa64mmfr1) >= ID_AA64MMFR1_PAN_IMPL) {
- sctlr = READ_SPECIALREG(sctlr_el1);
- sctlr &= ~SCTLR_SPAN;
- WRITE_SPECIALREG(sctlr_el1, sctlr);
- }
-
- /* Initialize debug registers. */
- WRITE_SPECIALREG(mdscr_el1, DBG_MDSCR_TDCC);
- WRITE_SPECIALREG(oslar_el1, 0);
+ cpu_init();
s = splhigh();
arm_intr_cpu_enable();
cpu_switchto(NULL, sched_chooseproc());
}
+void
+cpu_halt(void)
+{
+ struct cpu_info *ci = curcpu();
+
+ KERNEL_ASSERT_UNLOCKED();
+ SCHED_ASSERT_UNLOCKED();
+
+ intr_disable();
+ ci->ci_flags &= ~CPUF_RUNNING;
+#if NPSCI > 0
+ psci_cpu_off();
+#endif
+ for (;;)
+ __asm volatile("wfi");
+ /* NOTREACHED */
+}
+
void
cpu_kick(struct cpu_info *ci)
{
#endif
+#ifdef SUSPEND
+
+void cpu_hatch_primary(void);
+
+label_t cpu_suspend_jmpbuf;
+int cpu_suspended;
+
+void
+cpu_init_primary(void)
+{
+ cpu_init();
+
+ cpu_startclock();
+
+ cpu_suspended = 1;
+ longjmp(&cpu_suspend_jmpbuf);
+}
+
+int
+cpu_suspend_primary(void)
+{
+ extern uint64_t pmap_avail_kvo;
+ struct cpu_info *ci = curcpu();
+ paddr_t startaddr, data;
+ uint64_t ttbr1;
+
+ cpu_suspended = 0;
+ setjmp(&cpu_suspend_jmpbuf);
+ if (cpu_suspended) {
+ /* XXX wait for debug output from SCP on Allwinner A64 */
+ delay(200000);
+ return 0;
+ }
+
+ pmap_extract(pmap_kernel(), (vaddr_t)ci, &data);
+
+ __asm("mrs %x0, ttbr1_el1": "=r"(ttbr1));
+ ci->ci_ttbr1 = ttbr1;
+
+ cpu_dcache_wb_range((vaddr_t)&data, sizeof(paddr_t));
+ cpu_dcache_wb_range((vaddr_t)ci, sizeof(*ci));
+
+ startaddr = (vaddr_t)cpu_hatch_primary + pmap_avail_kvo;
+
+#if NPSCI > 0
+ psci_system_suspend(startaddr, data);
+#endif
+
+ return EOPNOTSUPP;
+}
+
+#ifdef MULTIPROCESSOR
+
+void
+cpu_resume_secondary(struct cpu_info *ci)
+{
+ struct proc *p;
+ struct pcb *pcb;
+ struct trapframe *tf;
+ struct switchframe *sf;
+ int timeout = 10000;
+
+ ci->ci_curproc = NULL;
+ ci->ci_curpcb = NULL;
+ ci->ci_curpm = NULL;
+ ci->ci_cpl = IPL_NONE;
+ ci->ci_ipending = 0;
+ ci->ci_idepth = 0;
+ ci->ci_flags &= ~CPUF_PRESENT;
+
+ ci->ci_mutex_level = 0;
+ ci->ci_ttbr1 = 0;
+
+ p = ci->ci_schedstate.spc_idleproc;
+ pcb = &p->p_addr->u_pcb;
+
+ tf = (struct trapframe *)((u_long)p->p_addr
+ + USPACE
+ - sizeof(struct trapframe)
+ - 0x10);
+
+ tf = (struct trapframe *)STACKALIGN(tf);
+ pcb->pcb_tf = tf;
+
+ sf = (struct switchframe *)tf - 1;
+ sf->sf_x19 = (uint64_t)sched_idle;
+ sf->sf_x20 = (uint64_t)ci;
+ sf->sf_lr = (uint64_t)proc_trampoline;
+ pcb->pcb_sp = (uint64_t)sf;
+
+ cpu_start_secondary(ci, 1, 0);
+ while ((ci->ci_flags & CPUF_PRESENT) == 0 && --timeout)
+ delay(1000);
+ if (timeout == 0) {
+ printf("%s: failed to spin up\n",
+ ci->ci_dev->dv_xname);
+ ci->ci_flags = 0;
+ }
+}
+
+#endif
+
+#endif
+
/*
* Dynamic voltage and frequency scaling implementation.
*/
-# $OpenBSD: genassym.cf,v 1.7 2021/05/16 10:40:24 jsg Exp $
+# $OpenBSD: genassym.cf,v 1.8 2022/07/13 09:28:18 kettenis Exp $
# $NetBSD: genassym.cf,v 1.27 2003/11/04 10:33:16 dsl Exp$
# Copyright (c) 1982, 1990 The Regents of the University of California.
struct cpu_info
member ci_curproc
-ifdef MULTIPROCESSOR
member ci_el1_stkend
member ci_ttbr1
member ci_self
-endif
struct proc
member p_addr
-/* $OpenBSD: locore.S,v 1.39 2021/09/02 10:48:52 kettenis Exp $ */
+/* $OpenBSD: locore.S,v 1.40 2022/07/13 09:28:18 kettenis Exp $ */
/*-
* Copyright (c) 2012-2014 Andrew Turner
* All rights reserved.
.text
#ifdef MULTIPROCESSOR
- .globl cpu_hatch
-cpu_hatch:
+ .globl cpu_hatch_secondary
+cpu_hatch_secondary:
/* Drop to EL1 */
bl drop_to_el1
ldr x1, [x0, #CI_EL1_STKEND]
mov sp, x1
- adr x1, .Lcpu_start_secondary
+ adr x1, .Lcpu_init_secondary
ldr x1, [x1]
blr x1
b .
.align 3
-.Lcpu_start_secondary:
- .xword cpu_start_secondary
-.Lpagetable_l0_ttbr0:
- .xword pagetable_l0_ttbr0
+.Lcpu_init_secondary:
+ .xword cpu_init_secondary
.Lcpu_hatch_ci:
.xword cpu_hatch_ci
.text
#endif
+
+#ifdef SUSPEND
+ .globl cpu_hatch_primary
+cpu_hatch_primary:
+ /* Drop to EL1 */
+ bl drop_to_el1
+
+ /* Get the virt -> phys offset */
+ bl get_virt_delta
+
+ /* Set up CPU info */
+ ldr x1, [x0, #CI_SELF]
+ msr tpidr_el1, x1
+
+ /* Enable the mmu */
+ adr x27, .Lpagetable_l0_ttbr0
+ ldr x27, [x27]
+ sub x27, x27, x29
+ ldr x26, [x0, #CI_TTBR1]
+ bl start_mmu
+
+ mrs x0, tpidr_el1
+ ldr x1, [x0, #CI_EL1_STKEND]
+ mov sp, x1
+
+ /* Restore registers. */
+ adr x1, .Lcpu_init_primary
+ ldr x1, [x1]
+ blr x1
+ b .
+
+ .align 3
+.Lcpu_init_primary:
+ .xword cpu_init_primary
+#endif
+
+ .align 3
+.Lpagetable_l0_ttbr0:
+ .xword pagetable_l0_ttbr0
+
-# $OpenBSD: GENERIC,v 1.231 2022/06/26 20:05:06 sthen Exp $
+# $OpenBSD: GENERIC,v 1.232 2022/07/13 09:28:18 kettenis Exp $
#
# GENERIC machine description file
#
option PCIVERBOSE
option USER_PCICONF # user-space PCI configuration
option USBVERBOSE
+option SUSPEND
makeoptions KERNEL_BASE_PHYS="0x00200000"
makeoptions KERNEL_BASE_VIRT="0xffffff8000200000"
-/* $OpenBSD: agintc.c,v 1.37 2022/06/16 20:44:09 kettenis Exp $ */
+/* $OpenBSD: agintc.c,v 1.38 2022/07/13 09:28:18 kettenis Exp $ */
/*
* Copyright (c) 2007, 2009, 2011, 2017 Dale Rahn <drahn@dalerahn.com>
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
struct agintc_dmamem *sc_prop;
struct agintc_dmamem *sc_pend;
struct interrupt_controller sc_ic;
- int sc_ipi_num[2]; /* id for NOP and DDB ipi */
- int sc_ipi_reason[MAXCPUS]; /* NOP or DDB caused */
- void *sc_ipi_irq[2]; /* irqhandle for each ipi */
+ int sc_ipi_num[3]; /* id for each ipi */
+ int sc_ipi_reason[MAXCPUS]; /* cause of ipi */
+ void *sc_ipi_irq[3]; /* irqhandle for each ipi */
};
struct agintc_softc *agintc_sc;
uint32_t agintc_r_ictlr(void);
int agintc_ipi_ddb(void *v);
+int agintc_ipi_halt(void *v);
int agintc_ipi_nop(void *v);
int agintc_ipi_combined(void *);
void agintc_send_ipi(struct cpu_info *, int);
int i, nbits, nintr;
int offset, nredist;
#ifdef MULTIPROCESSOR
- int nipi, ipiirq[2];
+ int nipi, ipiirq[3];
#endif
psw = intr_disable();
/* setup IPI interrupts */
/*
- * Ideally we want two IPI interrupts, one for NOP and one for
- * DDB, however we can survive if only one is available it is
- * possible that most are not available to the non-secure OS.
+ * Ideally we want three IPI interrupts, one for NOP, one for
+ * DDB and one for HALT. However we can survive if only one
+ * is available; it is possible that most are not available to
+ * the non-secure OS.
*/
nipi = 0;
for (i = 0; i < 16; i++) {
else
printf(", %d", i);
ipiirq[nipi++] = i;
- if (nipi == 2)
+ if (nipi == 3)
break;
}
agintc_ipi_combined, sc, "ipi");
sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[0];
+ sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[0];
break;
case 2:
+ sc->sc_ipi_irq[0] = agintc_intr_establish(ipiirq[0],
+ IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL,
+ agintc_ipi_nop, sc, "ipinop");
+ sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
+ sc->sc_ipi_irq[1] = agintc_intr_establish(ipiirq[1],
+ IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL,
+ agintc_ipi_combined, sc, "ipi");
+ sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1];
+ sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[1];
+ break;
+ case 3:
sc->sc_ipi_irq[0] = agintc_intr_establish(ipiirq[0],
IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL,
agintc_ipi_nop, sc, "ipinop");
IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL,
agintc_ipi_ddb, sc, "ipiddb");
sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1];
+ sc->sc_ipi_irq[2] = agintc_intr_establish(ipiirq[2],
+ IST_EDGE_RISING, IPL_IPI|IPL_MPSAFE, NULL,
+ agintc_ipi_halt, sc, "ipihalt");
+ sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[2];
break;
default:
panic("nipi unexpected number %d", nipi);
return 1;
}
+int
+agintc_ipi_halt(void *v)
+{
+ cpu_halt();
+ return 1;
+}
+
int
agintc_ipi_nop(void *v)
{
if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_DDB) {
sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP;
return agintc_ipi_ddb(v);
+ } else if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_HALT) {
+ sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP;
+ return agintc_ipi_halt(v);
} else {
return agintc_ipi_nop(v);
}
if (ci == curcpu() && id == ARM_IPI_NOP)
return;
- /* never overwrite IPI_DDB with IPI_NOP */
- if (id == ARM_IPI_DDB)
+ /* never overwrite IPI_DDB or IPI_HALT with IPI_NOP */
+ if (id == ARM_IPI_DDB || id == ARM_IPI_HALT)
sc->sc_ipi_reason[ci->ci_cpuid] = id;
/* will only send 1 cpu */
-/* $OpenBSD: ampintc.c,v 1.27 2022/01/02 20:00:21 kettenis Exp $ */
+/* $OpenBSD: ampintc.c,v 1.28 2022/07/13 09:28:18 kettenis Exp $ */
/*
* Copyright (c) 2007,2009,2011 Dale Rahn <drahn@openbsd.org>
*
struct evcount sc_spur;
struct interrupt_controller sc_ic;
int sc_ipi_reason[ICD_ICTR_CPU_M + 1];
- int sc_ipi_num[2];
+ int sc_ipi_num[3];
};
struct ampintc_softc *ampintc;
int ampintc_match(struct device *, void *, void *);
void ampintc_attach(struct device *, struct device *, void *);
+int ampintc_activate(struct device *, int);
+void ampintc_init(struct ampintc_softc *);
void ampintc_cpuinit(void);
int ampintc_spllower(int);
void ampintc_splx(int);
int ampintc_ipi_combined(void *);
int ampintc_ipi_nop(void *);
int ampintc_ipi_ddb(void *);
+int ampintc_ipi_halt(void *);
void ampintc_send_ipi(struct cpu_info *, int);
const struct cfattach ampintc_ca = {
- sizeof (struct ampintc_softc), ampintc_match, ampintc_attach
+ sizeof (struct ampintc_softc), ampintc_match, ampintc_attach,
+ NULL, ampintc_activate
};
struct cfdriver ampintc_cd = {
int i, nintr, ncpu;
uint32_t ictr;
#ifdef MULTIPROCESSOR
- int nipi, ipiirq[2];
+ int nipi, ipiirq[3];
#endif
ampintc = sc;
sc->sc_cpu_mask[curcpu()->ci_cpuid] =
bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(0));
- /* Disable all interrupts, clear all pending */
- for (i = 0; i < nintr/32; i++) {
- bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
- ICD_ICERn(i*32), ~0);
- bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
- ICD_ICPRn(i*32), ~0);
- }
- for (i = 0; i < nintr; i++) {
- /* lowest priority ?? */
- bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), 0xff);
- /* target no cpus */
- bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(i), 0);
- }
- for (i = 2; i < nintr/16; i++) {
- /* irq 32 - N */
- bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(i*16), 0);
- }
+ ampintc_init(sc);
/* software reset of the part? */
/* set protection bit (kernel only)? */
/* setup IPI interrupts */
/*
- * Ideally we want two IPI interrupts, one for NOP and one for
- * DDB, however we can survive if only one is available it is
- * possible that most are not available to the non-secure OS.
+ * Ideally we want three IPI interrupts, one for NOP, one for
+ * DDB and one for HALT. However we can survive if only one
+ * is available; it is possible that most are not available to
+ * the non-secure OS.
*/
nipi = 0;
for (i = 0; i < 16; i++) {
else
printf(", %d", i);
ipiirq[nipi++] = i;
- if (nipi == 2)
+ if (nipi == 3)
break;
}
IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_combined, sc, "ipi");
sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[0];
+ sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[0];
break;
case 2:
+ ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING,
+ IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_nop, sc, "ipinop");
+ sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
+ ampintc_intr_establish(ipiirq[1], IST_EDGE_RISING,
+ IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_combined, sc, "ipi");
+ sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1];
+ sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[1];
+ break;
+ case 3:
ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING,
IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_nop, sc, "ipinop");
sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
ampintc_intr_establish(ipiirq[1], IST_EDGE_RISING,
IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_ddb, sc, "ipiddb");
sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1];
+ ampintc_intr_establish(ipiirq[2], IST_EDGE_RISING,
+ IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_halt, sc, "ipihalt");
+ sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[2];
break;
default:
panic("nipi unexpected number %d", nipi);
simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
}
+int
+ampintc_activate(struct device *self, int act)
+{
+ struct ampintc_softc *sc = (struct ampintc_softc *)self;
+ struct cpu_info *ci;
+ int irq, min;
+
+ switch (act) {
+ case DVACT_RESUME:
+ for (irq = 0; irq < sc->sc_nintr; irq++) {
+ ci = sc->sc_handler[irq].iq_ci;
+ min = sc->sc_handler[irq].iq_irq_min;
+ if (min != IPL_NONE) {
+ ampintc_set_priority(irq, min);
+ ampintc_intr_enable(irq);
+ ampintc_route(irq, IRQ_ENABLE, ci);
+ } else {
+ ampintc_intr_disable(irq);
+ }
+ }
+
+ /* enable interrupts */
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3);
+ bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
+ break;
+ }
+
+ return 0;
+}
+
+void
+ampintc_init(struct ampintc_softc *sc)
+{
+ int i;
+
+ /* Disable all interrupts, clear all pending */
+ for (i = 0; i < sc->sc_nintr / 32; i++) {
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
+ ICD_ICERn(i * 32), ~0);
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
+ ICD_ICPRn(i * 32), ~0);
+ }
+ for (i = 0; i < sc->sc_nintr; i++) {
+ /* lowest priority ?? */
+ bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), 0xff);
+ /* target no cpus */
+ bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(i), 0);
+ }
+ for (i = 2; i < sc->sc_nintr / 16; i++) {
+ /* irq 32 - N */
+ bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
+ ICD_ICRn(i * 16), 0);
+ }
+}
+
void
ampintc_set_priority(int irq, int pri)
{
else
ampintc_route(irq, IRQ_DISABLE, curcpu());
}
+
+ /*
+ * If a secondary CPU is turned off from an IPI handler and
+ * the GIC did not go through a full reset (for example when
+ * we fail to suspend) the IPI might still be active. So
+ * signal EOI here to make sure new interrupts will be
+ * serviced.
+ */
+ ampintc_eoi(sc->sc_ipi_num[ARM_IPI_HALT]);
}
void
return 1;
}
+int
+ampintc_ipi_halt(void *v)
+{
+ cpu_halt();
+ return 1;
+}
+
int
ampintc_ipi_nop(void *v)
{
if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_DDB) {
sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP;
return ampintc_ipi_ddb(v);
+ } else if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_HALT) {
+ sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP;
+ return ampintc_ipi_halt(v);
} else {
return ampintc_ipi_nop(v);
}
if (ci == curcpu() && id == ARM_IPI_NOP)
return;
- /* never overwrite IPI_DDB with IPI_NOP */
- if (id == ARM_IPI_DDB)
+ /* never overwrite IPI_DDB or IPI_HALT with IPI_NOP */
+ if (id == ARM_IPI_DDB || id == ARM_IPI_HALT)
sc->sc_ipi_reason[ci->ci_cpuid] = id;
/* currently will only send to one cpu */
-/* $OpenBSD: aplintc.c,v 1.11 2022/04/10 10:43:34 kettenis Exp $ */
+/* $OpenBSD: aplintc.c,v 1.12 2022/07/13 09:28:18 kettenis Exp $ */
/*
* Copyright (c) 2021 Mark Kettenis
*
if (ci == curcpu() && reason == ARM_IPI_NOP)
return;
- /* never overwrite IPI_DDB with IPI_NOP */
- if (reason == ARM_IPI_DDB)
+ /* never overwrite IPI_DDB or IPI_HALT with IPI_NOP */
+ if (reason == ARM_IPI_DDB || reason == ARM_IPI_HALT)
sc->sc_ipi_reason[ci->ci_cpuid] = reason;
membar_producer();
-/* $OpenBSD: apm.c,v 1.16 2022/02/16 06:41:27 deraadt Exp $ */
+/* $OpenBSD: apm.c,v 1.17 2022/07/13 09:28:18 kettenis Exp $ */
/*-
* Copyright (c) 2001 Alexander Guy. All rights reserved.
#include <machine/acpiapm.h>
#include <machine/apmvar.h>
+#include "psci.h"
+#if NPSCI > 0
+#include <dev/fdt/pscivar.h>
+#endif
+
#if defined(APMDEBUG)
#define DPRINTF(x) printf x
#else
void
sleep_mp(void)
{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+
+ CPU_INFO_FOREACH(cii, ci) {
+ if (CPU_IS_PRIMARY(ci))
+ continue;
+ arm_send_ipi(ci, ARM_IPI_HALT);
+ while (ci->ci_flags & CPUF_RUNNING)
+ CPU_BUSY_CYCLE();
+ }
}
void
resume_mp(void)
{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+
+ CPU_INFO_FOREACH(cii, ci) {
+ if (CPU_IS_PRIMARY(ci))
+ continue;
+ cpu_resume_secondary(ci);
+ }
+ cpu_boot_secondary_processors();
}
#endif /* MULTIPROCESSOR */
int
sleep_showstate(void *v, int sleepmode)
{
- return 0;
+#if NPSCI > 0
+ if (sleepmode == SLEEP_SUSPEND && psci_can_suspend())
+ return 0;
+#endif
+
+ return EOPNOTSUPP;
}
int
int
gosleep(void *v)
{
- return EOPNOTSUPP;
+ return cpu_suspend_primary();
}
void
int
suspend_finish(void *v)
{
-#if 0
- extern int lid_action;
-
- acpi_record_event(sc, APM_NORMAL_RESUME);
- acpi_indicator(sc, ACPI_SST_WORKING);
-
- /* XXX won't work, there is no acpi thread on arm64 */
-
- /* If we woke up but all the lids are closed, go back to sleep */
- if (acpibtn_numopenlids() == 0 && lid_action != 0)
- acpi_addtask(sc, acpi_sleep_task, sc, sc->sc_state);
-#endif
return 0;
}
-/* $OpenBSD: cpu.h,v 1.26 2022/06/16 20:45:42 kettenis Exp $ */
+/* $OpenBSD: cpu.h,v 1.27 2022/07/13 09:28:19 kettenis Exp $ */
/*
* Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
*
u_int32_t ci_pkg_id;
struct proc *ci_curproc;
+ struct pcb *ci_curpcb;
struct pmap *ci_curpm;
u_int32_t ci_randseed;
- struct pcb *ci_curpcb;
- struct pcb *ci_idle_pcb;
-
u_int32_t ci_ctrl; /* The CPU control register */
uint32_t ci_cpl;
void (*ci_flush_bp)(void);
+ uint64_t ci_ttbr1;
+ vaddr_t ci_el1_stkend;
+
struct opp_table *ci_opp_table;
volatile int ci_opp_idx;
volatile int ci_opp_max;
#ifdef MULTIPROCESSOR
struct srp_hazard ci_srp_hazards[SRP_HAZARD_NUM];
volatile int ci_flags;
- uint64_t ci_ttbr1;
- vaddr_t ci_el1_stkend;
volatile int ci_ddb_paused;
#define CI_DDB_RUNNING 0
restore_daif(daif);
}
+void cpu_halt(void);
void cpu_startclock(void);
+int cpu_suspend_primary(void);
+void cpu_resume_secondary(struct cpu_info *);
void delay (unsigned);
#define DELAY(x) delay(x)
-/* $OpenBSD: intr.h,v 1.18 2021/05/17 17:25:13 kettenis Exp $ */
+/* $OpenBSD: intr.h,v 1.19 2022/07/13 09:28:19 kettenis Exp $ */
/*
* Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
#define ARM_IPI_NOP 0
#define ARM_IPI_DDB 1
+#define ARM_IPI_HALT 2
#ifdef DIAGNOSTIC
/*