1 /* $OpenBSD: cpu.c,v 1.47 2023/10/24 13:20:09 claudio Exp $ */
2
3 /*
4 * Copyright (c) 1998-2003 Michael Shalayeff
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/proc.h>
33 #include <sys/reboot.h>
34
35 #include <uvm/uvm_extern.h>
36
37 #include <machine/cpufunc.h>
38 #include <machine/pdc.h>
39 #include <machine/reg.h>
40 #include <machine/iomod.h>
41 #include <machine/autoconf.h>
42
43 #include <hppa/dev/cpudevs.h>
44
45 struct cpu_softc {
46 struct device sc_dev;
47 };
48
49 #ifdef MULTIPROCESSOR
50 struct cpu_info *cpu_hatch_info;
51 static volatile int start_secondary_cpu;
52 #endif
53
54 int cpumatch(struct device *, void *, void *);
55 void cpuattach(struct device *, struct device *, void *);
56
57 const struct cfattach cpu_ca = {
58 sizeof(struct cpu_softc), cpumatch, cpuattach
59 };
60
61 struct cfdriver cpu_cd = {
62 NULL, "cpu", DV_DULL
63 };
64
65 int
cpumatch(struct device * parent,void * cfdata,void * aux)66 cpumatch(struct device *parent, void *cfdata, void *aux)
67 {
68 struct cfdata *cf = cfdata;
69 struct confargs *ca = aux;
70
71 /* probe any 1.0, 1.1 or 2.0 */
72 if (ca->ca_type.iodc_type != HPPA_TYPE_NPROC ||
73 ca->ca_type.iodc_sv_model != HPPA_NPROC_HPPA)
74 return 0;
75
76 if (cf->cf_unit >= MAXCPUS)
77 return 0;
78
79 return 1;
80 }
81
82 void
cpuattach(struct device * parent,struct device * self,void * aux)83 cpuattach(struct device *parent, struct device *self, void *aux)
84 {
85 /* machdep.c */
86 extern struct pdc_model pdc_model;
87 extern struct pdc_cache pdc_cache;
88 extern struct pdc_btlb pdc_btlb;
89 extern u_int cpu_ticksnum, cpu_ticksdenom;
90 extern u_int fpu_enable;
91 /* clock.c */
92 extern int itmr_intr(void *);
93 /* ipi.c */
94 extern int hppa_ipi_intr(void *);
95
96 struct confargs *ca = (struct confargs *)aux;
97 struct cpu_info *ci;
98 u_int mhz = 100 * cpu_ticksnum / cpu_ticksdenom;
99 int cpuno = self->dv_unit;
100 struct pglist mlist;
101 struct vm_page *m;
102 const char *p;
103 int error;
104
105 ci = &cpu_info[cpuno];
106 ci->ci_dev = self;
107 ci->ci_cpuid = cpuno;
108 ci->ci_hpa = ca->ca_hpa;
109
110 /* Allocate stack for spin up and FPU emulation. */
111 TAILQ_INIT(&mlist);
112 error = uvm_pglistalloc(PAGE_SIZE, 0, -1L, 0, 0, &mlist, 1,
113 UVM_PLA_NOWAIT);
114 if (error) {
115 printf(": unable to allocate CPU stack!\n");
116 return;
117 }
118 m = TAILQ_FIRST(&mlist);
119 ci->ci_stack = VM_PAGE_TO_PHYS(m);
120
121 printf (": %s ", cpu_typename);
122 if (pdc_model.hvers) {
123 static const char lvls[4][4] = { "0", "1", "1.5", "2" };
124
125 printf("L%s-%c ", lvls[pdc_model.pa_lvl], "AB"[pdc_model.mc]);
126 }
127
128 printf ("%d", mhz / 100);
129 if (mhz % 100 > 9)
130 printf(".%02d", mhz % 100);
131 printf("MHz");
132
133 if (fpu_enable) {
134 extern u_int fpu_version;
135 u_int32_t ver[2];
136
137 mtctl(fpu_enable, CR_CCR);
138 __asm volatile(
139 "fstds %%fr0,0(%0)\n\t"
140 "copr,0,0\n\t"
141 "fstds %%fr0,0(%0)"
142 :: "r" (&ver) : "memory");
143 mtctl(0, CR_CCR);
144 fpu_version = HPPA_FPUVER(ver[0]);
145 printf(", FPU %s rev %d",
146 hppa_mod_info(HPPA_TYPE_FPU, fpu_version >> 5),
147 fpu_version & 0x1f);
148 }
149
150 printf("\n%s: ", self->dv_xname);
151 p = "";
152 if (!pdc_cache.dc_conf.cc_sh) {
153 printf("%uK(%db/l) Icache, ",
154 pdc_cache.ic_size / 1024, pdc_cache.ic_conf.cc_line * 16);
155 p = "D";
156 }
157
158 printf("%uK(%db/l) wr-%s %scache, ",
159 pdc_cache.dc_size / 1024, pdc_cache.dc_conf.cc_line * 16,
160 pdc_cache.dc_conf.cc_wt? "thru" : "back", p);
161
162 p = "";
163 if (!pdc_cache.dt_conf.tc_sh) {
164 printf("%u ITLB, ", pdc_cache.it_size);
165 p = "D";
166 }
167 printf("%u %scoherent %sTLB",
168 pdc_cache.dt_size, pdc_cache.dt_conf.tc_cst? "" : "in", p);
169
170 if (pdc_btlb.finfo.num_c)
171 printf(", %u BTLB", pdc_btlb.finfo.num_c);
172 else if (pdc_btlb.finfo.num_i || pdc_btlb.finfo.num_d)
173 printf(", %u/%u D/I BTLBs",
174 pdc_btlb.finfo.num_i, pdc_btlb.finfo.num_d);
175
176 cpu_intr_establish(IPL_CLOCK, 31, itmr_intr, NULL, "clock");
177 #ifdef MULTIPROCESSOR
178 cpu_intr_establish(IPL_IPI, 30, hppa_ipi_intr, NULL, "ipi");
179 #endif
180
181 printf("\n");
182 }
183
184 #ifdef MULTIPROCESSOR
185 void
cpu_boot_secondary_processors(void)186 cpu_boot_secondary_processors(void)
187 {
188 struct cpu_info *ci;
189 struct iomod *cpu;
190 int i, j;
191
192 /* Initialise primary CPU. */
193 ci = curcpu();
194 ci->ci_flags |= CPUF_RUNNING;
195 hppa_ipi_init(ci);
196
197 for (i = 0; i < HPPA_MAXCPUS; i++) {
198
199 ci = &cpu_info[i];
200 if (ci->ci_cpuid == 0)
201 continue;
202
203 ci->ci_randseed = (arc4random() & 0x7fffffff) + 1;
204
205 clockqueue_init(&ci->ci_queue);
206 sched_init_cpu(ci);
207
208 /* Release the specified CPU by triggering an EIR{0}. */
209 cpu_hatch_info = ci;
210 cpu = (struct iomod *)(ci->ci_hpa);
211 cpu->io_eir = 0;
212 asm volatile ("sync" ::: "memory");
213
214 /* Wait for CPU to wake up... */
215 j = 0;
216 while (!(ci->ci_flags & CPUF_RUNNING) && j++ < 10000)
217 delay(1000);
218 if (!(ci->ci_flags & CPUF_RUNNING))
219 printf("failed to hatch cpu %i!\n", ci->ci_cpuid);
220 }
221
222 /* Release secondary CPUs. */
223 start_secondary_cpu = 1;
224 asm volatile ("sync" ::: "memory");
225 }
226
227 void
cpu_hw_init(void)228 cpu_hw_init(void)
229 {
230 struct cpu_info *ci = curcpu();
231
232 /* Purge TLB and flush caches. */
233 ptlball();
234 ficacheall();
235 fdcacheall();
236
237 /* Enable address translations. */
238 ci->ci_psw = PSL_I | PSL_Q | PSL_P | PSL_C | PSL_D;
239 ci->ci_psw |= (cpu_info[0].ci_psw & PSL_O);
240 }
241
242 void
cpu_hatch(void)243 cpu_hatch(void)
244 {
245 struct cpu_info *ci = curcpu();
246
247 /* Initialise IPIs. */
248 hppa_ipi_init(ci);
249
250 /* Initialise clock. */
251 mtctl((1U << 31), CR_EIRR);
252 ci->ci_mask |= (1U << 31);
253 cpu_startclock();
254
255 /* Enable interrupts. */
256 mtctl(ci->ci_mask, CR_EIEM);
257
258 ncpus++;
259 ci->ci_flags |= CPUF_RUNNING;
260
261 /* Wait for additional CPUs to spinup. */
262 while (!start_secondary_cpu)
263 ;
264
265 sched_toidle();
266 }
267
268 void
cpu_unidle(struct cpu_info * ci)269 cpu_unidle(struct cpu_info *ci)
270 {
271 if (ci != curcpu())
272 hppa_ipi_send(ci, HPPA_IPI_NOP);
273 }
274 #endif
275
276 void
need_resched(struct cpu_info * ci)277 need_resched(struct cpu_info *ci)
278 {
279 ci->ci_want_resched = 1;
280
281 /* There's a risk we'll be called before the idle threads start */
282 if (ci->ci_curproc) {
283 setsoftast(ci->ci_curproc);
284 cpu_unidle(ci);
285 }
286 }
287