1/* $NetBSD: cpu.h,v 1.16 2024/08/04 08:16:25 skrll Exp $ */
2
3/*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas of 3am Software Foundry.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#ifndef _RISCV_CPU_H_
33#define _RISCV_CPU_H_
34
35#if defined(_KERNEL) || defined(_KMEMUSER)
36
37struct clockframe {
38 vaddr_t cf_epc;
39 register_t cf_status;
40 int cf_intr_depth;
41};
42
43#define CLKF_USERMODE(cf) (((cf)->cf_status & SR_SPP) == 0)
44#define CLKF_PC(cf) ((cf)->cf_epc)
45#define CLKF_INTR(cf) ((cf)->cf_intr_depth > 1)
46
47#include <sys/cpu_data.h>
48#include <sys/device_if.h>
49#include <sys/evcnt.h>
50#include <sys/intr.h>
51
52struct cpu_info {
53 struct cpu_data ci_data;
54 device_t ci_dev;
55 cpuid_t ci_cpuid;
56 struct lwp *ci_curlwp;
57 struct lwp *ci_onproc; /* current user LWP / kthread */
58 struct lwp *ci_softlwps[SOFTINT_COUNT];
59 struct trapframe *ci_ddb_regs;
60
61 uint64_t ci_lastintr;
62 uint64_t ci_lastintr_scheduled;
63 struct evcnt ci_ev_timer;
64 struct evcnt ci_ev_timer_missed;
65
66 u_long ci_cpu_freq; /* CPU frequency */
67 int ci_mtx_oldspl;
68 int ci_mtx_count;
69 int ci_cpl;
70 volatile u_int ci_intr_depth;
71
72 int ci_want_resched __aligned(COHERENCY_UNIT);
73 u_int ci_softints;
74
75 tlb_asid_t ci_pmap_asid_cur;
76
77 union pmap_segtab *ci_pmap_user_segtab;
78#ifdef _LP64
79 union pmap_segtab *ci_pmap_user_seg0tab;
80#endif
81
82 struct evcnt ci_ev_fpu_saves;
83 struct evcnt ci_ev_fpu_loads;
84 struct evcnt ci_ev_fpu_reenables;
85
86 struct pmap_tlb_info *ci_tlb_info;
87
88#ifdef MULTIPROCESSOR
89 volatile u_long ci_flags;
90#define CPUF_PRIMARY __BIT(0) /* CPU is primary CPU */
91#define CPUF_PRESENT __BIT(1) /* CPU is present */
92#define CPUF_RUNNING __BIT(2) /* CPU is running */
93#define CPUF_PAUSED __BIT(3) /* CPU is paused */
94
95 void *ci_intcsoftc;
96 volatile u_long ci_request_ipis;
97 /* bitmask of IPIs requested */
98 u_long ci_active_ipis; /* bitmask of IPIs being serviced */
99
100 struct evcnt ci_evcnt_all_ipis; /* aggregated IPI counter */
101 struct evcnt ci_evcnt_per_ipi[NIPIS]; /* individual IPI counters */
102 struct evcnt ci_evcnt_synci_onproc_rqst;
103 struct evcnt ci_evcnt_synci_deferred_rqst;
104 struct evcnt ci_evcnt_synci_ipi_rqst;
105
106 kcpuset_t *ci_shootdowncpus;
107 kcpuset_t *ci_multicastcpus;
108 kcpuset_t *ci_watchcpus;
109 kcpuset_t *ci_ddbcpus;
110#endif
111
112#if defined(GPROF) && defined(MULTIPROCESSOR)
113 struct gmonparam *ci_gmon; /* MI per-cpu GPROF */
114#endif
115};
116
117#endif /* _KERNEL || _KMEMUSER */
118
119#ifdef _KERNEL
120
121extern struct cpu_info cpu_info_store[];
122extern cpuid_t cpu_bphartid;
123extern u_int cpu_hartindex[];
124
125#ifdef MULTIPROCESSOR
126
127void cpu_hatch(struct cpu_info *, unsigned long);
128
129void cpu_init_secondary_processor(u_int);
130void cpu_boot_secondary_processors(void);
131void cpu_mpstart(void);
132bool cpu_hatched_p(u_int);
133
134void cpu_clr_mbox(u_int);
135void cpu_set_hatched(u_int);
136
137
138void cpu_halt(void);
139void cpu_halt_others(void);
140bool cpu_is_paused(cpuid_t);
141void cpu_pause(void);
142void cpu_pause_others(void);
143void cpu_resume(cpuid_t);
144void cpu_resume_others(void);
145void cpu_debug_dump(void);
146
147extern kcpuset_t *cpus_running;
148extern kcpuset_t *cpus_hatched;
149extern kcpuset_t *cpus_paused;
150extern kcpuset_t *cpus_resumed;
151extern kcpuset_t *cpus_halted;
152
153/*
154 * definitions of cpu-dependent requirements
155 * referenced in generic code
156 */
157
158/*
159 * Send an inter-processor interrupt to each other CPU (excludes curcpu())
160 */
161void cpu_broadcast_ipi(int);
162
163/*
164 * Send an inter-processor interrupt to CPUs in kcpuset (excludes curcpu())
165 */
166void cpu_multicast_ipi(const kcpuset_t *, int);
167
168/*
169 * Send an inter-processor interrupt to another CPU.
170 */
171int cpu_send_ipi(struct cpu_info *, int);
172
173#endif
174
175struct lwp;
176static inline struct cpu_info *lwp_getcpu(struct lwp *);
177
178register struct lwp *riscv_curlwp __asm("tp");
179#define curlwp riscv_curlwp
180#define curcpu() lwp_getcpu(curlwp)
181#define curpcb ((struct pcb *)lwp_getpcb(curlwp))
182
183static inline cpuid_t
184cpu_number(void)
185{
186#ifdef MULTIPROCESSOR
187 return curcpu()->ci_cpuid;
188#else
189 return 0;
190#endif
191}
192
193void cpu_proc_fork(struct proc *, struct proc *);
194void cpu_signotify(struct lwp *);
195void cpu_need_proftick(struct lwp *l);
196void cpu_boot_secondary_processors(void);
197
198#define CPU_INFO_ITERATOR cpuid_t
199#ifdef MULTIPROCESSOR
200#define CPU_IS_PRIMARY(ci) ((ci)->ci_flags & CPUF_PRIMARY)
201#define CPU_INFO_FOREACH(cii, ci) \
202 cii = 0, ci = &cpu_info_store[0]; \
203 ci != NULL; \
204 cii++, ncpu ? (ci = cpu_infos[cii]) \
205 : (ci = NULL)
206#else
207#define CPU_IS_PRIMARY(ci) true
208#define CPU_INFO_FOREACH(cii, ci) \
209 (cii) = 0, (ci) = curcpu(); (cii) == 0; (cii)++
210#endif
211
212#define CPU_INFO_CURPMAP(ci) (curlwp->l_proc->p_vmspace->vm_map.pmap)
213
214static inline void
215cpu_dosoftints(void)
216{
217 extern void dosoftints(void);
218 struct cpu_info * const ci = curcpu();
219 if (ci->ci_intr_depth == 0
220 && (ci->ci_data.cpu_softints >> ci->ci_cpl) > 0)
221 dosoftints();
222}
223
224static inline bool
225cpu_intr_p(void)
226{
227 return curcpu()->ci_intr_depth > 0;
228}
229
230#define LWP_PC(l) cpu_lwp_pc(l)
231
232vaddr_t cpu_lwp_pc(struct lwp *);
233
234static inline void
235cpu_idle(void)
236{
237 asm volatile("wfi" ::: "memory");
238}
239
240#endif /* _KERNEL */
241
242#endif /* _RISCV_CPU_H_ */