Various MP changes.

This commit is contained in:
matt 2014-03-28 21:39:09 +00:00
parent 39ac7250f3
commit d6e299a97b
7 changed files with 300 additions and 186 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: arm32_boot.c,v 1.6 2014/03/03 08:52:30 matt Exp $ */
/* $NetBSD: arm32_boot.c,v 1.7 2014/03/28 21:39:09 matt Exp $ */
/*
* Copyright (c) 2002, 2003, 2005 Genetec Corporation. All rights reserved.
@ -123,7 +123,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: arm32_boot.c,v 1.6 2014/03/03 08:52:30 matt Exp $");
__KERNEL_RCSID(1, "$NetBSD: arm32_boot.c,v 1.7 2014/03/28 21:39:09 matt Exp $");
#include "opt_ddb.h"
#include "opt_kgdb.h"
@ -132,6 +132,8 @@ __KERNEL_RCSID(1, "$NetBSD: arm32_boot.c,v 1.6 2014/03/03 08:52:30 matt Exp $");
#include <sys/reboot.h>
#include <sys/cpu.h>
#include <sys/intr.h>
#include <sys/atomic.h>
#include <sys/device.h>
#include <uvm/uvm_extern.h>
@ -320,19 +322,34 @@ cpu_hatch(struct cpu_info *ci, cpuid_t cpuid, void (*md_cpu_init)(struct cpu_inf
*/
splhigh();
#ifdef VERBOSE_INIT_ARM
printf("%s(%s): ", __func__, ci->ci_data.cpu_name);
#endif
uint32_t mpidr = armreg_mpidr_read();
if (mpidr & MPIDR_MT) {
ci->ci_data.cpu_smt_id = mpidr & MPIDR_AFF0;
ci->ci_data.cpu_core_id = mpidr & MPIDR_AFF1;
ci->ci_data.cpu_package_id = mpidr & MPIDR_AFF2;
} else {
ci->ci_data.cpu_core_id = mpidr & MPIDR_AFF0;
ci->ci_data.cpu_package_id = mpidr & MPIDR_AFF1;
}
/*
* Make sure we have the right vector page.
*/
#ifdef VERBOSE_INIT_ARM
printf(" vectors");
#endif
arm32_vector_init(systempage.pv_va, ARM_VEC_ALL);
/*
* Initialize the stack for each mode (we are already running on the SVC32
* stack of the idlelwp).
* Initialize the stack for each mode (we are already running on the
* SVC32 stack of the idlelwp).
*/
#ifdef VERBOSE_INIT_ARM
printf(" stacks");
#endif
set_stackptr(PSR_FIQ32_MODE,
fiqstack.pv_va + cpu_index(ci) * FIQ_STACK_SIZE * PAGE_SIZE);
set_stackptr(PSR_IRQ32_MODE,
@ -345,13 +362,14 @@ cpu_hatch(struct cpu_info *ci, cpuid_t cpuid, void (*md_cpu_init)(struct cpu_inf
ci->ci_lastlwp = NULL;
ci->ci_pmap_lastuser = NULL;
#ifdef ARM_MMU_EXTENDED
#ifdef VERBOSE_INIT_ARM
printf(" tlb");
#endif
/*
* Attach to the tlb.
*/
ci->ci_pmap_cur = pmap_kernel();
ci->ci_pmap_asid_cur = KERNEL_PID;
pmap_tlb_info_attach(&pmap_tlb0_info, ci);
#endif
#ifdef CPU_CORTEX
@ -364,24 +382,32 @@ cpu_hatch(struct cpu_info *ci, cpuid_t cpuid, void (*md_cpu_init)(struct cpu_inf
}
#endif
aprint_naive("%s", device_xname(ci->ci_dev));
aprint_normal("%s", device_xname(ci->ci_dev));
identify_arm_cpu(ci->ci_dev, ci);
#ifdef VERBOSE_INIT_ARM
printf(" vfp");
#endif
vfp_attach(ci);
#ifdef VERBOSE_INIT_ARM
printf(" interrupts");
#endif
/*
* Let the interrupts do what they need to on this CPU.
*/
intr_cpu_init(ci);
#ifdef VERBOSE_INIT_ARM
printf(" md(%p)", md_cpu_init);
#endif
if (md_cpu_init != NULL)
(*md_cpu_init)(ci);
#if 0
/*
* Tell the MI code we are alive!
*/
printf(" mi_cpu");
mi_cpu_running(ci);
#endif
#ifdef VERBOSE_INIT_ARM
printf(" done!\n");
#endif
atomic_and_32(&arm_cpu_mbox, ~(1 << cpuid));
__asm __volatile("sev; sev; sev");
}
#endif /* MULTIPROCESSOR */

View File

@ -1,4 +1,4 @@
/* $NetBSD: arm32_machdep.c,v 1.101 2014/03/03 08:15:36 matt Exp $ */
/* $NetBSD: arm32_machdep.c,v 1.102 2014/03/28 21:39:09 matt Exp $ */
/*
* Copyright (c) 1994-1998 Mark Brinicombe.
@ -42,7 +42,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: arm32_machdep.c,v 1.101 2014/03/03 08:15:36 matt Exp $");
__KERNEL_RCSID(0, "$NetBSD: arm32_machdep.c,v 1.102 2014/03/28 21:39:09 matt Exp $");
#include "opt_modular.h"
#include "opt_md.h"
@ -683,16 +683,17 @@ cpu_uarea_alloc_idlelwp(struct cpu_info *ci)
void
cpu_boot_secondary_processors(void)
{
uint32_t mbox;
kcpuset_export_u32(kcpuset_attached, &mbox, sizeof(mbox));
#ifdef VERBOSE_ARM_INIT
printf("%s: writing mbox with %#x\n", __func__, mbox);
#ifdef VERBOSE_INIT_ARM
printf("%s: writing mbox with %#x\n", __func__, arm_cpu_hatched);
#endif
atomic_swap_32(&arm_cpu_mbox, mbox);
arm_cpu_mbox = arm_cpu_hatched;
membar_producer();
#ifdef _ARM_ARCH_7
__asm __volatile("sev; sev; sev");
#endif
while (arm_cpu_mbox) {
__asm("wfe");
}
}
void
@ -701,23 +702,7 @@ xc_send_ipi(struct cpu_info *ci)
KASSERT(kpreempt_disabled());
KASSERT(curcpu() != ci);
if (ci) {
/* Unicast, remote CPU */
printf("%s: -> %s", __func__, ci->ci_data.cpu_name);
intr_ipi_send(ci->ci_kcpuset, IPI_XCALL);
} else {
printf("%s: -> !%s", __func__, ci->ci_data.cpu_name);
/* Broadcast to all but ourselves */
kcpuset_t *kcp;
kcpuset_create(&kcp, (ci != NULL));
KASSERT(kcp != NULL);
kcpuset_copy(kcp, kcpuset_running);
kcpuset_clear(kcp, cpu_index(ci));
intr_ipi_send(kcp, IPI_XCALL);
kcpuset_destroy(kcp);
}
printf("\n");
intr_ipi_send(ci != NULL ? ci->ci_kcpuset : NULL, IPI_XCALL);
}
#endif /* MULTIPROCESSOR */

View File

@ -1,4 +1,4 @@
/* $NetBSD: cpu.c,v 1.103 2014/03/24 20:06:31 christos Exp $ */
/* $NetBSD: cpu.c,v 1.104 2014/03/28 21:39:09 matt Exp $ */
/*
* Copyright (c) 1995 Mark Brinicombe.
@ -46,7 +46,7 @@
#include <sys/param.h>
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.103 2014/03/24 20:06:31 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.104 2014/03/28 21:39:09 matt Exp $");
#include <sys/systm.h>
#include <sys/conf.h>
@ -64,15 +64,15 @@ extern const char *cpu_arch;
#ifdef MULTIPROCESSOR
volatile u_int arm_cpu_hatched = 0;
u_int arm_cpu_max = 0;
uint32_t arm_cpu_mbox __cacheline_aligned = 0;
uint32_t arm_cpu_marker[2] __cacheline_aligned = { 0, 0 };
volatile uint32_t arm_cpu_mbox __cacheline_aligned = 0;
uint32_t arm_cpu_marker[2] __cacheline_aligned = { 0, 0 };
u_int arm_cpu_max = 1;
#endif
/* Prototypes */
void identify_arm_cpu(device_t dv, struct cpu_info *);
void identify_cortex_caches(device_t dv);
void identify_features(device_t dv);
void identify_arm_cpu(device_t, struct cpu_info *);
void identify_cortex_caches(device_t);
void identify_features(device_t);
/*
* Identify the master (boot) CPU
@ -99,11 +99,22 @@ cpu_attach(device_t dv, cpuid_t id)
KASSERT(ci != NULL);
ci->ci_cpl = IPL_HIGH;
ci->ci_cpuid = id;
uint32_t mpidr = armreg_mpidr_read();
if (mpidr & MPIDR_MT) {
ci->ci_data.cpu_smt_id = mpidr & MPIDR_AFF0;
ci->ci_data.cpu_core_id = mpidr & MPIDR_AFF1;
ci->ci_data.cpu_package_id = mpidr & MPIDR_AFF2;
} else {
ci->ci_data.cpu_core_id = mpidr & MPIDR_AFF0;
ci->ci_data.cpu_package_id = mpidr & MPIDR_AFF1;
}
ci->ci_data.cpu_core_id = id;
ci->ci_data.cpu_cc_freq = cpu_info_store.ci_data.cpu_cc_freq;
ci->ci_arm_cpuid = cpu_info_store.ci_arm_cpuid;
ci->ci_arm_cputype = cpu_info_store.ci_arm_cputype;
ci->ci_arm_cpurev = cpu_info_store.ci_arm_cpurev;
ci->ci_ctrl = cpu_info_store.ci_ctrl;
ci->ci_undefsave[2] = cpu_info_store.ci_undefsave[2];
cpu_info[ci->ci_cpuid] = ci;
if ((arm_cpu_hatched & (1 << id)) == 0) {
ci->ci_dev = dv;
@ -157,15 +168,27 @@ cpu_attach(device_t dv, cpuid_t id)
NULL, xname, "permission abort (S)");
evcnt_attach_dynamic_nozero(&ci->ci_abt_evs[FAULT_PERM_P], EVCNT_TYPE_TRAP,
NULL, xname, "permission abort (P)");
evcnt_attach_dynamic_nozero(&ci->ci_und_ev, EVCNT_TYPE_TRAP,
NULL, xname, "undefined insn traps");
evcnt_attach_dynamic_nozero(&ci->ci_und_cp15_ev, EVCNT_TYPE_TRAP,
NULL, xname, "undefined cp15 insn traps");
#ifdef MULTIPROCESSOR
/*
* and we are done if this is a secondary processor.
*/
if (!CPU_IS_PRIMARY(ci)) {
if (id != 0) {
#if 1
aprint_naive("\n");
aprint_normal("\n");
#else
aprint_naive(": %s\n", cpu_getmodel());
aprint_normal(": %s\n", cpu_getmodel());
#endif
mi_cpu_attach(ci);
#ifdef ARM_MMU_EXTENDED
pmap_tlb_info_attach(&pmap_tlb0_info, ci);
#endif
return;
}
#endif
@ -204,7 +227,7 @@ cpu_attach(device_t dv, cpuid_t id)
}
#endif
vfp_attach(); /* XXX SMP */
vfp_attach(ci); /* XXX SMP */
}
enum cpu_class {
@ -585,48 +608,58 @@ print_cache_info(device_t dv, struct arm_cache_info *info, u_int level)
}
}
void
identify_arm_cpu(device_t dv, struct cpu_info *ci)
static enum cpu_class
identify_arm_model(uint32_t cpuid, char *buf, size_t len)
{
enum cpu_class cpu_class = CPU_CLASS_NONE;
const u_int cpuid = ci->ci_arm_cpuid;
const char * const xname = device_xname(dv);
const char *steppingstr;
int i;
if (cpuid == 0) {
aprint_error("Processor failed probe - no CPU ID\n");
return;
}
for (i = 0; cpuids[i].cpuid != 0; i++)
if (cpuids[i].cpuid == (cpuid & CPU_ID_CPU_MASK)) {
cpu_class = cpuids[i].cpu_class;
cpu_arch = cpuids[i].cpu_arch;
steppingstr = cpuids[i].cpu_steppings[cpuid &
CPU_ID_REVISION_MASK];
cpu_setmodel("%s%s%s (%s V%s core)",
cpuids[i].cpu_classname,
for (const struct cpuidtab *id = cpuids; id->cpuid != 0; id++) {
if (id->cpuid == (cpuid & CPU_ID_CPU_MASK)) {
const char *steppingstr =
id->cpu_steppings[cpuid & CPU_ID_REVISION_MASK];
cpu_arch = id->cpu_arch;
cpu_class = id->cpu_class;
snprintf(buf, len, "%s%s%s (%s V%s core)",
id->cpu_classname,
steppingstr[0] == '*' ? "" : " ",
&steppingstr[steppingstr[0] == '*'],
cpu_classes[cpu_class].class_name,
cpu_arch);
break;
return cpu_class;
}
}
if (cpuids[i].cpuid == 0)
cpu_setmodel("unknown CPU (ID = 0x%x)", cpuid);
snprintf(buf, len, "unknown CPU (ID = 0x%x)", cpuid);
return cpu_class;
}
void
identify_arm_cpu(device_t dv, struct cpu_info *ci)
{
const uint32_t arm_cpuid = ci->ci_arm_cpuid;
const char * const xname = device_xname(dv);
char model[128];
if (arm_cpuid == 0) {
aprint_error("Processor failed probe - no CPU ID\n");
return;
}
const enum cpu_class cpu_class = identify_arm_model(arm_cpuid,
model, sizeof(model));
if (ci->ci_cpuid == 0) {
cpu_setmodel("%s", model);
}
if (ci->ci_data.cpu_cc_freq != 0) {
char freqbuf[8];
humanize_number(freqbuf, sizeof(freqbuf), ci->ci_data.cpu_cc_freq,
"Hz", 1000);
aprint_naive(": %s %s\n", freqbuf, cpu_getmodel());
aprint_normal(": %s %s\n", freqbuf, cpu_getmodel());
aprint_naive(": %s %s\n", freqbuf, model);
aprint_normal(": %s %s\n", freqbuf, model);
} else {
aprint_naive(": %s\n", cpu_getmodel());
aprint_normal(": %s\n", cpu_getmodel());
aprint_naive(": %s\n", model);
aprint_normal(": %s\n", model);
}
aprint_normal("%s:", xname);
@ -679,7 +712,7 @@ identify_arm_cpu(device_t dv, struct cpu_info *ci)
aprint_normal("\n");
if (CPU_ID_CORTEX_P(cpuid) || CPU_ID_ARM11_P(cpuid) || CPU_ID_MV88SV58XX_P(cpuid)) {
if (CPU_ID_CORTEX_P(arm_cpuid) || CPU_ID_ARM11_P(arm_cpuid) || CPU_ID_MV88SV58XX_P(arm_cpuid)) {
identify_features(dv);
}
@ -791,6 +824,7 @@ identify_features(device_t dv)
cpu_memory_model_features[2] = armreg_mmfr2_read();
cpu_memory_model_features[3] = armreg_mmfr3_read();
#if 0
if (__SHIFTOUT(cpu_memory_model_features[3], __BITS(23,20))) {
/*
* Updates to the translation tables do not require a clean
@ -799,6 +833,7 @@ identify_features(device_t dv)
*/
pmap_needs_pte_sync = 0;
}
#endif
cpu_processor_features[0] = armreg_pfr0_read();
cpu_processor_features[1] = armreg_pfr1_read();

View File

@ -1,4 +1,4 @@
/* $NetBSD: gic.c,v 1.6 2014/03/04 15:24:38 matt Exp $ */
/* $NetBSD: gic.c,v 1.7 2014/03/28 21:39:09 matt Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
@ -28,16 +28,19 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "opt_ddb.h"
#define _INTR_PRIVATE
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.6 2014/03/04 15:24:38 matt Exp $");
__KERNEL_RCSID(0, "$NetBSD: gic.c,v 1.7 2014/03/28 21:39:09 matt Exp $");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/device.h>
#include <sys/evcnt.h>
#include <sys/intr.h>
#include <sys/cpu.h>
#include <sys/proc.h>
#include <sys/xcall.h> /* for xc_ipi_handler */
@ -92,6 +95,9 @@ static struct armgic_softc {
uint32_t sc_gic_type;
uint32_t sc_gic_valid_lines[1024/32];
uint32_t sc_enabled_local;
#ifdef MULTIPROCESSOR
uint32_t sc_mptargets;
#endif
} armgic_softc = {
.sc_pic = {
.pic_ops = &armgic_picops,
@ -341,6 +347,11 @@ armgic_establish_irq(struct pic_softc *pic, struct intrsource *is)
* to the primary cpu.
*/
targets &= ~(0xff << byte_shift);
#ifdef MULTIPROCESSOR
if (is->is_mpsafe) {
targets |= sc->sc_mptargets;
} else
#endif
targets |= 1 << byte_shift;
gicd_write(sc, targets_reg, targets);
@ -361,6 +372,14 @@ armgic_establish_irq(struct pic_softc *pic, struct intrsource *is)
pic->pic_name, is->is_irq, cfg, new_cfg);
#endif
}
#ifdef MULTIPROCESSOR
} else {
/*
* All group 0 interrupts are per processor and MPSAFE by
* default.
*/
is->is_mpsafe = true;
#endif
}
/*
@ -411,18 +430,42 @@ armgic_cpu_init_priorities(struct armgic_softc *sc)
}
}
static void
armgic_cpu_init_targets(struct armgic_softc *sc)
{
/*
* Update the mpsafe targets
*/
for (size_t irq = 32; irq < sc->sc_gic_lines; irq++) {
struct intrsource * const is = sc->sc_pic.pic_sources[irq];
const bus_size_t targets_reg = GICD_ITARGETSRn(irq / 4);
if (is != NULL && is->is_mpsafe) {
const u_int byte_shift = 0xff << (8 * (irq & 3));
uint32_t targets = gicd_read(sc, targets_reg);
targets |= sc->sc_mptargets << byte_shift;
gicd_write(sc, targets_reg, targets);
}
}
}
void
armgic_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
{
struct armgic_softc * const sc = PICTOSOFTC(pic);
if (!CPU_IS_PRIMARY(ci) && sc->sc_enabled_local) {
armgic_cpu_init_priorities(sc);
}
sc->sc_mptargets |= 1 << cpu_index(ci);
KASSERTMSG(ci->ci_cpl == IPL_HIGH, "ipl %d not IPL_HIGH", ci->ci_cpl);
if (!CPU_IS_PRIMARY(ci)) {
if (sc->sc_mptargets != 1) {
armgic_cpu_init_targets(sc);
}
if (sc->sc_enabled_local) {
armgic_cpu_init_priorities(sc);
gicd_write(sc, GICD_ISENABLERn(0),
sc->sc_enabled_local);
}
}
gicc_write(sc, GICC_PMR, armgic_ipl_to_priority(ci->ci_cpl)); // set PMR
gicc_write(sc, GICC_CTRL, GICC_CTRL_V1_Enable); // enable interrupt
if (!CPU_IS_PRIMARY(ci) && sc->sc_enabled_local)
gicd_write(sc, GICD_ISENABLERn(0), sc->sc_enabled_local);
cpsie(I32_bit); // allow IRQ exceptions
}
@ -431,19 +474,28 @@ armgic_ipi_send(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
{
struct armgic_softc * const sc = PICTOSOFTC(pic);
#if 0
if (ipi == IPI_NOP) {
__asm __volatile("sev");
return;
}
#endif
uint32_t targets;
kcpuset_export_u32(kcp, &targets, sizeof(targets));
uint32_t sgir = __SHIFTOUT(ARMGIC_SGI_IPIBASE + ipi, GICD_SGIR_SGIINTID);
sgir |= __SHIFTOUT(targets, GICD_SGIR_TargetList);
uint32_t sgir = __SHIFTIN(ARMGIC_SGI_IPIBASE + ipi, GICD_SGIR_SGIINTID);
if (kcp != NULL) {
uint32_t targets;
kcpuset_export_u32(kcp, &targets, sizeof(targets));
sgir |= __SHIFTIN(targets, GICD_SGIR_TargetList);
sgir |= GICD_SGIR_TargetListFilter_List;
} else {
if (ncpu == 1)
return;
sgir |= GICD_SGIR_TargetListFilter_NotMe;
}
printf("%s: %s: %#x", __func__, curcpu()->ci_data.cpu_name, sgir);
//printf("%s: %s: %#x", __func__, curcpu()->ci_data.cpu_name, sgir);
gicd_write(sc, GICD_SGIR, sgir);
printf("\n");
//printf("\n");
}
#endif
@ -553,9 +605,13 @@ armgic_attach(device_t parent, device_t self, void *aux)
pic_ipi_nop, (void *)-1);
intr_establish(ARMGIC_SGI_IPIBASE + IPI_XCALL, IPL_VM, IST_EDGE,
pic_ipi_xcall, (void *)-1);
#if 0 /* Not needed */
intr_establish(ARMGIC_SGI_IPIBASE + IPI_NOP, IPL_VM, IST_EDGE,
pic_ipi_nop, (void *)-1);
intr_establish(ARMGIC_SGI_IPIBASE + IPI_SHOOTDOWN, IPL_VM, IST_EDGE,
pic_ipi_shootdown, (void *)-1);
#ifdef DDB
intr_establish(ARMGIC_SGI_IPIBASE + IPI_DDB, IPL_HIGH, IST_EDGE,
pic_ipi_ddb, NULL);
#endif
#ifdef __HAVE_PREEMPTION
intr_establish(ARMGIC_SGI_IPIBASE + IPI_KPREEMPT, IPL_VM, IST_EDGE,

View File

@ -1,4 +1,4 @@
/* $NetBSD: gic_reg.h,v 1.1 2012/09/01 00:03:14 matt Exp $ */
/* $NetBSD: gic_reg.h,v 1.2 2014/03/28 21:39:09 matt Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
@ -199,4 +199,14 @@
#define GICv1_ICCHPIR GICC_HPPIR
#define GICv1_ICCIIDR GICC_IIDR
/* GICv2m (MSI) */
#define GIC_MSI_TYPER 0x0008
#define GIC_MSI_SETSPI 0x0040
#define GIC_MSI_PIDR2 0x0fe8
#define GIC_MSI_IIDR 0x0ffc
#define GIC_MSI_TYPER_BASE __BITS(25,16) // Starting SPI of MSIs
#define GIC_MSI_TYPER_NUMBER __BITS(9,0) // Count of MSIs
#endif /* !_ARM_CORTEX_GICREG_H_ */

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore.h,v 1.15 2014/03/18 07:05:46 matt Exp $ */
/* $NetBSD: locore.h,v 1.16 2014/03/28 21:39:09 matt Exp $ */
/*
* Copyright (c) 1994-1996 Mark Brinicombe.
@ -164,7 +164,11 @@ extern int cpu_memory_model_features[4];
extern int cpu_processor_features[2];
extern int cpu_media_and_vfp_features[2];
extern bool arm_has_tlbiasid_p;
#ifdef MULTIPROCESSOR
extern u_int arm_cpu_max;
extern volatile u_int arm_cpu_hatched;
#endif
#if !defined(CPU_ARMV7)
#define CPU_IS_ARMV7_P() false
@ -229,15 +233,41 @@ read_thumb_insn(vaddr_t va, bool user_p)
return insn;
}
static inline void
arm_dmb(void)
{
if (CPU_IS_ARMV6_P())
armreg_dmb_write(0);
else if (CPU_IS_ARMV7_P())
__asm __volatile("dmb");
}
static inline void
arm_dsb(void)
{
if (CPU_IS_ARMV6_P())
armreg_dsb_write(0);
else if (CPU_IS_ARMV7_P())
__asm __volatile("dsb");
}
static inline void
arm_isb(void)
{
if (CPU_IS_ARMV6_P())
armreg_isb_write(0);
else if (CPU_IS_ARMV7_P())
__asm __volatile("isb");
}
/*
* Random cruft
*/
struct lwp;
/* locore.S */
void atomic_set_bit(u_int *, u_int);
void atomic_clear_bit(u_int *, u_int);
/* cpu.c */
void identify_arm_cpu(device_t, struct cpu_info *);
/* cpuswitch.S */
struct pcb;
@ -259,7 +289,7 @@ void swi_handler(trapframe_t *);
void ucas_ras_check(trapframe_t *);
/* vfp_init.c */
void vfp_attach(void);
void vfp_attach(struct cpu_info *);
void vfp_discardcontext(bool);
void vfp_savecontext(void);
void vfp_kernel_acquire(void);

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfp_init.c,v 1.36 2014/03/18 07:03:22 matt Exp $ */
/* $NetBSD: vfp_init.c,v 1.37 2014/03/28 21:39:09 matt Exp $ */
/*
* Copyright (c) 2008 ARM Ltd
@ -141,10 +141,6 @@ const pcu_ops_t arm_vfp_ops = {
.pcu_state_release = vfp_state_release,
};
struct evcnt vfpevent_use;
struct evcnt vfpevent_reuse;
struct evcnt vfpevent_fpe;
/* determine what bits can be changed */
uint32_t vfp_fpscr_changable = VFP_FPSCR_CSUM;
/* default to run fast */
@ -173,10 +169,6 @@ vfp_test(u_int address, u_int insn, trapframe_t *frame, int fault_code)
uint32_t vfp_fpscr_changable = VFP_FPSCR_CSUM|VFP_FPSCR_ESUM|VFP_FPSCR_RMODE;
#endif /* FPU_VFP */
struct evcnt vfp_fpscr_ev =
EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "VFP", "FPSCR traps");
EVCNT_ATTACH_STATIC(vfp_fpscr_ev);
static int
vfp_fpscr_handler(u_int address, u_int insn, trapframe_t *frame, int fault_code)
{
@ -216,7 +208,7 @@ vfp_fpscr_handler(u_int address, u_int insn, trapframe_t *frame, int fault_code)
pcb->pcb_vfp.vfp_fpscr |= *regp & vfp_fpscr_changable;
}
vfp_fpscr_ev.ev_count++;
curcpu()->ci_vfp_evs[0].ev_count++;
frame->tf_pc += INSN_SIZE;
return 0;
@ -228,50 +220,37 @@ vfp_fpscr_handler(u_int address, u_int insn, trapframe_t *frame, int fault_code)
* instructions.
*/
void
vfp_attach(void)
vfp_attach(struct cpu_info *ci)
{
install_coproc_handler(VFP_COPROC, vfp_fpscr_handler);
if (CPU_IS_PRIMARY(ci)) {
install_coproc_handler(VFP_COPROC, vfp_fpscr_handler);
}
evcnt_attach_dynamic(&ci->ci_vfp_evs[0], EVCNT_TYPE_TRAP, NULL,
ci->ci_cpuname, "vfp fpscr traps");
}
#else
#if 0
static bool
vfp_patch_branch(uintptr_t code, uintptr_t func, uintptr_t newfunc)
{
for (;; code += sizeof(uint32_t)) {
uint32_t insn = *(uint32_t *)code;
if ((insn & 0xffd08000) == 0xe8908000) /* ldm ... { pc } */
return false;
if ((insn & 0xfffffff0) == 0xe12fff10) /* bx rN */
return false;
if ((insn & 0xf1a0f000) == 0xe1a0f000) /* mov pc, ... */
return false;
if ((insn >> 25) != 0x75) /* not b/bl insn */
continue;
intptr_t imm26 = ((int32_t)insn << 8) >> 6;
if (code + imm26 + 8 == func) {
int32_t imm24 = (newfunc - (code + 8)) >> 2;
uint32_t new_insn = (insn & 0xff000000)
| (imm24 & 0xffffff);
KASSERTMSG((uint32_t)((imm24 >> 24) + 1) <= 1, "%x",
((imm24 >> 24) + 1));
*(uint32_t *)code = new_insn;
cpu_idcache_wbinv_range(code, sizeof(uint32_t));
return true;
}
}
}
#endif
void
vfp_attach(void)
vfp_attach(struct cpu_info *ci)
{
struct cpu_info * const ci = curcpu();
const char *model = NULL;
if (CPU_ID_ARM11_P(curcpu()->ci_arm_cpuid)
|| CPU_ID_MV88SV58XX_P(curcpu()->ci_arm_cpuid)
|| CPU_ID_CORTEX_P(curcpu()->ci_arm_cpuid)) {
if (CPU_ID_ARM11_P(ci->ci_arm_cpuid)
|| CPU_ID_MV88SV58XX_P(ci->ci_arm_cpuid)
|| CPU_ID_CORTEX_P(ci->ci_arm_cpuid)) {
#if 0
const uint32_t nsacr = armreg_nsacr_read();
const uint32_t nsacr_vfp = __BITS(VFP_COPROC,VFP_COPROC2);
if ((nsacr & nsacr_vfp) != nsacr_vfp) {
aprint_normal_dev(ci->ci_dev, "VFP access denied\n");
install_coproc_handler(VFP_COPROC, vfp_fpscr_handler);
ci->ci_vfp_id = 0;
evcnt_attach_dynamic(&ci->ci_vfp_evs[0],
EVCNT_TYPE_TRAP, NULL, ci->ci_cpuname,
"vfp fpscr traps");
return;
}
#endif
const uint32_t cpacr_vfp = CPACR_CPn(VFP_COPROC);
const uint32_t cpacr_vfp2 = CPACR_CPn(VFP_COPROC2);
@ -281,15 +260,6 @@ vfp_attach(void)
uint32_t cpacr = armreg_cpacr_read();
cpacr |= __SHIFTIN(CPACR_ALL, cpacr_vfp);
cpacr |= __SHIFTIN(CPACR_ALL, cpacr_vfp2);
#if 0
if (CPU_ID_CORTEX_P(curcpu()->ci_arm_cpuid)) {
/*
* Disable access to the upper 16 FP registers and NEON.
*/
cpacr |= CPACR_V7_D32DIS;
cpacr |= CPACR_V7_ASEDIS;
}
#endif
armreg_cpacr_write(cpacr);
/*
@ -302,6 +272,9 @@ vfp_attach(void)
aprint_normal_dev(ci->ci_dev, "No VFP detected\n");
install_coproc_handler(VFP_COPROC, vfp_fpscr_handler);
ci->ci_vfp_id = 0;
evcnt_attach_dynamic(&ci->ci_vfp_evs[0],
EVCNT_TYPE_TRAP, NULL, ci->ci_cpuname,
"vfp fpscr traps");
return;
}
}
@ -337,8 +310,12 @@ vfp_attach(void)
case FPU_VFP_CORTEXA8:
case FPU_VFP_CORTEXA9:
case FPU_VFP_CORTEXA15:
model = "NEON MPE (VFP 3.0+)";
cpu_neon_present = 1;
if (armreg_cpacr_read() & CPACR_V7_ASEDIS) {
model = "VFP 4.0+";
} else {
model = "NEON MPE (VFP 3.0+)";
cpu_neon_present = 1;
}
break;
default:
aprint_normal_dev(ci->ci_dev, "unrecognized VFP version %#x\n",
@ -357,50 +334,45 @@ vfp_attach(void)
uint32_t f0 = armreg_mvfr0_read();
uint32_t f1 = armreg_mvfr0_read();
aprint_normal("vfp%d at %s: %s%s%s%s%s\n",
device_unit(curcpu()->ci_dev),
device_xname(curcpu()->ci_dev),
device_unit(ci->ci_dev),
device_xname(ci->ci_dev),
model,
((f0 & ARM_MVFR0_ROUNDING_MASK) ? ", rounding" : ""),
((f0 & ARM_MVFR0_EXCEPT_MASK) ? ", exceptions" : ""),
((f1 & ARM_MVFR1_D_NAN_MASK) ? ", NaN propogation" : ""),
((f1 & ARM_MVFR1_FTZ_MASK) ? ", denormals" : ""));
aprint_verbose("vfp%d: mvfr: [0]=%#x [1]=%#x\n",
device_unit(curcpu()->ci_dev), f0, f1);
if (cpu_media_and_vfp_features[0] & ARM_MVFR0_ROUNDING_MASK) {
vfp_fpscr_changable |= VFP_FPSCR_RMODE;
}
if (cpu_media_and_vfp_features[0] & ARM_MVFR0_EXCEPT_MASK) {
vfp_fpscr_changable |= VFP_FPSCR_ESUM;
}
// If hardware supports propogation of NaNs, select it.
if (cpu_media_and_vfp_features[1] & ARM_MVFR1_D_NAN_MASK) {
vfp_fpscr_default &= ~VFP_FPSCR_DN;
vfp_fpscr_changable |= VFP_FPSCR_DN;
}
// If hardware supports denormalized numbers, use it.
if (cpu_media_and_vfp_features[1] & ARM_MVFR1_FTZ_MASK) {
vfp_fpscr_default &= ~VFP_FPSCR_FZ;
vfp_fpscr_changable |= VFP_FPSCR_FZ;
device_unit(ci->ci_dev), f0, f1);
if (CPU_IS_PRIMARY(ci)) {
if (f0 & ARM_MVFR0_ROUNDING_MASK) {
vfp_fpscr_changable |= VFP_FPSCR_RMODE;
}
if (f1 & ARM_MVFR0_EXCEPT_MASK) {
vfp_fpscr_changable |= VFP_FPSCR_ESUM;
}
// If hardware supports propogation of NaNs, select it.
if (f1 & ARM_MVFR1_D_NAN_MASK) {
vfp_fpscr_default &= ~VFP_FPSCR_DN;
vfp_fpscr_changable |= VFP_FPSCR_DN;
}
// If hardware supports denormalized numbers, use it.
if (cpu_media_and_vfp_features[1] & ARM_MVFR1_FTZ_MASK) {
vfp_fpscr_default &= ~VFP_FPSCR_FZ;
vfp_fpscr_changable |= VFP_FPSCR_FZ;
}
}
}
evcnt_attach_dynamic(&vfpevent_use, EVCNT_TYPE_MISC, NULL,
"VFP", "coproc use");
evcnt_attach_dynamic(&vfpevent_reuse, EVCNT_TYPE_MISC, NULL,
"VFP", "coproc re-use");
evcnt_attach_dynamic(&vfpevent_fpe, EVCNT_TYPE_TRAP, NULL,
"VFP", "coproc fault");
evcnt_attach_dynamic(&ci->ci_vfp_evs[0], EVCNT_TYPE_MISC, NULL,
ci->ci_cpuname, "vfp coproc use");
evcnt_attach_dynamic(&ci->ci_vfp_evs[1], EVCNT_TYPE_MISC, NULL,
ci->ci_cpuname, "vfp coproc re-use");
evcnt_attach_dynamic(&ci->ci_vfp_evs[2], EVCNT_TYPE_TRAP, NULL,
ci->ci_cpuname, "vfp coproc fault");
install_coproc_handler(VFP_COPROC, vfp_handler);
install_coproc_handler(VFP_COPROC2, vfp_handler);
#ifdef CPU_CORTEX
install_coproc_handler(CORE_UNKNOWN_HANDLER, neon_handler);
#endif
#if 0
vfp_patch_branch((uintptr_t)pmap_copy_page_generic,
(uintptr_t)bcopy_page, (uintptr_t)bcopy_page_vfp);
vfp_patch_branch((uintptr_t)pmap_zero_page_generic,
(uintptr_t)bzero_page, (uintptr_t)bzero_page_vfp);
#endif
}
/* The real handler for VFP bounces. */
@ -434,7 +406,7 @@ vfp_handler(u_int address, u_int insn, trapframe_t *frame, int fault_code)
ksiginfo_t ksi;
KASSERT(fpexc & VFP_FPEXC_EN);
vfpevent_fpe.ev_count++;
curcpu()->ci_vfp_evs[2].ev_count++;
/*
* Need the clear the exception condition so any signal
@ -533,10 +505,10 @@ vfp_state_load(lwp_t *l, u_int flags)
*/
if (__predict_false((flags & PCU_LOADED) == 0)) {
KASSERT(flags & PCU_RELOAD);
vfpevent_use.ev_count++;
curcpu()->ci_vfp_evs[0].ev_count++;
pcb->pcb_vfp.vfp_fpscr = vfp_fpscr_default;
} else {
vfpevent_reuse.ev_count++;
curcpu()->ci_vfp_evs[1].ev_count++;
}
uint32_t fpexc = armreg_fpexc_read();