1 1.39 rin /* $NetBSD: cpu.c,v 1.39 2022/10/05 08:18:00 rin Exp $ */ 2 1.1 eeh 3 1.1 eeh /* 4 1.1 eeh * Copyright 2001 Wasabi Systems, Inc. 5 1.1 eeh * All rights reserved. 6 1.1 eeh * 7 1.1 eeh * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc. 8 1.1 eeh * 9 1.1 eeh * Redistribution and use in source and binary forms, with or without 10 1.1 eeh * modification, are permitted provided that the following conditions 11 1.1 eeh * are met: 12 1.1 eeh * 1. Redistributions of source code must retain the above copyright 13 1.1 eeh * notice, this list of conditions and the following disclaimer. 14 1.1 eeh * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 eeh * notice, this list of conditions and the following disclaimer in the 16 1.1 eeh * documentation and/or other materials provided with the distribution. 17 1.1 eeh * 3. All advertising materials mentioning features or use of this software 18 1.1 eeh * must display the following acknowledgement: 19 1.1 eeh * This product includes software developed for the NetBSD Project by 20 1.1 eeh * Wasabi Systems, Inc. 21 1.1 eeh * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 1.1 eeh * or promote products derived from this software without specific prior 23 1.1 eeh * written permission. 24 1.1 eeh * 25 1.1 eeh * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 1.1 eeh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 1.1 eeh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 1.1 eeh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 1.1 eeh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 1.1 eeh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 1.1 eeh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 1.1 eeh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 1.1 eeh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 1.1 eeh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 1.1 eeh * POSSIBILITY OF SUCH DAMAGE. 36 1.1 eeh */ 37 1.16 lukem 38 1.16 lukem #include <sys/cdefs.h> 39 1.39 rin __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.39 2022/10/05 08:18:00 rin Exp $"); 40 1.1 eeh 41 1.1 eeh #include <sys/param.h> 42 1.1 eeh #include <sys/systm.h> 43 1.1 eeh #include <sys/device.h> 44 1.24 freza #include <sys/evcnt.h> 45 1.30 matt #include <sys/cpu.h> 46 1.1 eeh 47 1.13 thorpej #include <uvm/uvm_extern.h> 48 1.13 thorpej 49 1.23 thorpej #include <prop/proplib.h> 50 1.23 thorpej 51 1.30 matt #include <powerpc/ibm4xx/cpu.h> 52 1.4 simonb #include <powerpc/ibm4xx/dev/plbvar.h> 53 1.1 eeh 54 1.1 eeh struct cputab { 55 1.25 freza u_int version; 56 1.25 freza u_int mask; 57 1.19 scw const char *name; 58 1.32 matt struct cache_info ci; 59 1.1 eeh }; 60 1.32 matt 61 1.31 matt static const struct cputab models[] = { 62 1.32 matt { 63 1.32 matt .version = PVR_401A1, 64 1.32 matt .mask = 0xffff0000, 65 1.32 matt .name = "401A1", 66 1.32 matt .ci = { 67 1.32 matt .dcache_size = 1024, 68 1.32 matt .dcache_line_size = 16, 69 1.38 simonb .icache_size = 2048, 70 1.32 matt .icache_line_size = 16, 71 1.32 matt } 72 1.32 matt }, { 73 1.32 matt .version = PVR_401B2, 74 1.32 matt .mask = 0xffff0000, 75 1.32 matt .name = "401B21", 76 1.32 matt .ci = { 77 1.32 matt .dcache_size = 8192, 78 1.32 matt .dcache_line_size = 16, 79 1.32 matt .icache_size = 16384, 80 1.32 matt .icache_line_size = 16, 81 1.32 matt } 82 1.32 matt }, { 83 1.32 matt .version = PVR_401C2, 84 1.32 matt .mask = 0xffff0000, 85 1.32 matt .name = "401C2", 86 1.32 matt .ci = { 87 1.32 matt .dcache_size = 8192, 88 1.32 matt .dcache_line_size = 16, 89 1.32 matt .icache_size = 0, 90 1.32 matt .icache_line_size = 16, 91 1.32 matt } 92 1.32 matt }, { 93 1.32 matt .version = PVR_401D2, 94 1.32 matt .mask = 0xffff0000, 95 1.32 matt .name = "401D2", 96 1.32 matt .ci = { 97 1.38 simonb .dcache_size = 2048, 98 1.32 matt .dcache_line_size = 16, 99 1.32 matt .icache_size = 4096, 100 1.32 matt .icache_line_size = 16, 101 1.32 matt } 102 1.32 matt }, { 103 1.32 matt .version = PVR_401E2, 104 1.32 matt .mask = 0xffff0000, 105 1.32 matt .name = "401E2", 106 1.32 matt .ci = { 107 1.32 matt .dcache_size = 0, 108 1.32 matt .dcache_line_size = 16, 109 1.32 matt .icache_size = 0, 110 1.32 matt .icache_line_size = 16, 111 1.32 matt } 112 1.32 matt }, { 113 1.32 matt .version = PVR_401F2, 114 1.32 matt .mask = 0xffff0000, 115 1.32 matt .name = "401F2", 116 1.32 matt .ci = { 117 1.32 matt .dcache_size = 2048, 118 1.32 matt .dcache_line_size = 16, 119 1.38 simonb .icache_size = 2048, 120 1.32 matt .icache_line_size = 16, 121 1.32 matt } 122 1.32 matt }, { 123 1.32 matt .version = PVR_401G2, 124 1.32 matt .mask = 0xffff0000, 125 1.32 matt .name = "401G2", 126 1.32 matt .ci = { 127 1.38 simonb .dcache_size = 2048, 128 1.32 matt .dcache_line_size = 16, 129 1.32 matt .icache_size = 8192, 130 1.32 matt .icache_line_size = 16, 131 1.32 matt } 132 1.32 matt }, { 133 1.35 rin .version = PVR_403GA, /* XXX no MMU */ 134 1.35 rin .mask = 0xffffff00, 135 1.35 rin .name = "403GA", 136 1.35 rin .ci = { 137 1.35 rin .dcache_size = 1024, 138 1.35 rin .dcache_line_size = 16, 139 1.35 rin .icache_size = 2048, 140 1.35 rin .icache_line_size = 16, 141 1.35 rin } 142 1.35 rin }, { 143 1.35 rin .version = PVR_403GB, /* XXX no MMU */ 144 1.35 rin .mask = 0xffffff00, 145 1.35 rin .name = "403GB", 146 1.35 rin .ci = { 147 1.35 rin .dcache_size = 1024, 148 1.35 rin .dcache_line_size = 16, 149 1.35 rin .icache_size = 2048, 150 1.35 rin .icache_line_size = 16, 151 1.35 rin } 152 1.35 rin }, { 153 1.35 rin .version = PVR_403GC, 154 1.35 rin .mask = 0xffffff00, 155 1.35 rin .name = "403GC", 156 1.35 rin .ci = { 157 1.35 rin .dcache_size = 1024, 158 1.35 rin .dcache_line_size = 16, 159 1.35 rin .icache_size = 2048, 160 1.35 rin .icache_line_size = 16, 161 1.35 rin } 162 1.35 rin }, { 163 1.35 rin .version = PVR_403GCX, 164 1.35 rin .mask = 0xffffff00, 165 1.35 rin .name = "403GCX", 166 1.32 matt .ci = { 167 1.32 matt .dcache_size = 8192, 168 1.32 matt .dcache_line_size = 16, 169 1.32 matt .icache_size = 16384, 170 1.32 matt .icache_line_size = 16, 171 1.32 matt } 172 1.32 matt }, { 173 1.32 matt .version = PVR_405GP, 174 1.32 matt .mask = 0xffff0000, 175 1.32 matt .name = "405GP", 176 1.32 matt .ci = { 177 1.32 matt .dcache_size = 8192, 178 1.32 matt .dcache_line_size = 32, 179 1.37 rin .icache_size = 16384, 180 1.32 matt .icache_line_size = 32, 181 1.32 matt } 182 1.32 matt }, { 183 1.32 matt .version = PVR_405GPR, 184 1.32 matt .mask = 0xffff0000, 185 1.32 matt .name = "405GPr", 186 1.32 matt .ci = { 187 1.32 matt .dcache_size = 16384, 188 1.32 matt .dcache_line_size = 32, 189 1.32 matt .icache_size = 16384, 190 1.32 matt .icache_line_size = 32, 191 1.32 matt } 192 1.32 matt }, { 193 1.32 matt .version = PVR_405D5X1, 194 1.32 matt .mask = 0xfffff000, 195 1.32 matt .name = "Xilinx Virtex II Pro", 196 1.32 matt .ci = { 197 1.32 matt .dcache_size = 16384, 198 1.32 matt .dcache_line_size = 32, 199 1.32 matt .icache_size = 16384, 200 1.32 matt .icache_line_size = 32, 201 1.32 matt } 202 1.32 matt }, { 203 1.32 matt .version = PVR_405D5X2, 204 1.32 matt .mask = 0xfffff000, 205 1.32 matt .name = "Xilinx Virtex 4 FX", 206 1.32 matt .ci = { 207 1.32 matt .dcache_size = 16384, 208 1.32 matt .dcache_line_size = 32, 209 1.32 matt .icache_size = 16384, 210 1.32 matt .icache_line_size = 32, 211 1.32 matt } 212 1.32 matt }, { 213 1.32 matt .version = PVR_405EX, 214 1.32 matt .mask = 0xffff0000, 215 1.32 matt .name = "405EX", 216 1.32 matt .ci = { 217 1.32 matt .dcache_size = 16384, 218 1.32 matt .dcache_line_size = 32, 219 1.32 matt .icache_size = 16384, 220 1.32 matt .icache_line_size = 32, 221 1.32 matt } 222 1.32 matt }, { 223 1.32 matt .version = 0, 224 1.32 matt .mask = 0, 225 1.32 matt .name = NULL, 226 1.32 matt .ci = { 227 1.32 matt /* 228 1.32 matt * Unknown CPU type. For safety we'll specify a 229 1.32 matt * cache with a 4-byte line size. That way cache 230 1.32 matt * flush routines won't miss any lines. 231 1.32 matt */ 232 1.32 matt .dcache_line_size = 4, 233 1.32 matt .icache_line_size = 4, 234 1.32 matt }, 235 1.32 matt }, 236 1.1 eeh }; 237 1.1 eeh 238 1.29 matt static int cpumatch(device_t, cfdata_t, void *); 239 1.29 matt static void cpuattach(device_t, device_t, void *); 240 1.1 eeh 241 1.32 matt CFATTACH_DECL_NEW(cpu, 0, cpumatch, cpuattach, NULL, NULL); 242 1.1 eeh 243 1.1 eeh int ncpus; 244 1.1 eeh 245 1.24 freza struct cpu_info cpu_info[1] = { 246 1.24 freza { 247 1.24 freza /* XXX add more ci_ev_* as we teach 4xx about them */ 248 1.24 freza .ci_ev_clock = EVCNT_INITIALIZER(EVCNT_TYPE_INTR, 249 1.24 freza NULL, "cpu0", "clock"), 250 1.24 freza .ci_ev_statclock = EVCNT_INITIALIZER(EVCNT_TYPE_INTR, 251 1.24 freza NULL, "cpu0", "stat clock"), 252 1.26 ad .ci_curlwp = &lwp0, 253 1.24 freza } 254 1.24 freza }; 255 1.17 shige 256 1.32 matt bool cpufound; 257 1.1 eeh 258 1.1 eeh static int 259 1.29 matt cpumatch(device_t parent, cfdata_t cf, void *aux) 260 1.1 eeh { 261 1.4 simonb struct plb_attach_args *paa = aux; 262 1.1 eeh 263 1.1 eeh /* make sure that we're looking for a CPU */ 264 1.8 thorpej if (strcmp(paa->plb_name, cf->cf_name) != 0) 265 1.3 simonb return (0); 266 1.1 eeh 267 1.1 eeh return !cpufound; 268 1.1 eeh } 269 1.1 eeh 270 1.1 eeh static void 271 1.29 matt cpuattach(device_t parent, device_t self, void *aux) 272 1.1 eeh { 273 1.32 matt struct cpu_info * const ci = curcpu(); 274 1.32 matt const struct cputab *cp; 275 1.25 freza u_int processor_freq; 276 1.23 thorpej prop_number_t freq; 277 1.2 eeh 278 1.23 thorpej freq = prop_dictionary_get(board_properties, "processor-frequency"); 279 1.23 thorpej KASSERT(freq != NULL); 280 1.23 thorpej processor_freq = (unsigned int) prop_number_integer_value(freq); 281 1.1 eeh 282 1.32 matt cpufound = true; 283 1.1 eeh ncpus++; 284 1.1 eeh 285 1.32 matt const u_int pvr = mfpvr(); 286 1.32 matt for (cp = models; cp->name != NULL; cp++) { 287 1.32 matt if ((pvr & cp->mask) == cp->version) { 288 1.33 christos cpu_setmodel("%s", cp->name); 289 1.1 eeh break; 290 1.32 matt } 291 1.1 eeh } 292 1.32 matt if (__predict_false(cp->name == NULL)) 293 1.33 christos cpu_setmodel("Version 0x%x", pvr); 294 1.25 freza 295 1.36 rin aprint_normal(": %uMHz %s (PVR 0x%08x)\n", 296 1.32 matt (processor_freq + 500000) / 1000000, 297 1.33 christos (cp->name != NULL ? cpu_getmodel() : "unknown model"), 298 1.32 matt pvr); 299 1.1 eeh 300 1.1 eeh cpu_probe_cache(); 301 1.1 eeh 302 1.25 freza /* We would crash later on anyway so just make the reason obvious */ 303 1.32 matt if (ci->ci_ci.icache_size == 0 && ci->ci_ci.dcache_size == 0) 304 1.32 matt panic("%s: %s: could not detect cache size", 305 1.32 matt __func__, device_xname(self)); 306 1.32 matt 307 1.32 matt aprint_normal_dev(self, "%uKB/%uB L1 instruction cache\n", 308 1.32 matt ci->ci_ci.icache_size / 1024, ci->ci_ci.icache_line_size); 309 1.32 matt aprint_normal_dev(self, "%uKB/%uB L1 data cache\n", 310 1.32 matt ci->ci_ci.dcache_size / 1024, ci->ci_ci.dcache_line_size); 311 1.1 eeh } 312 1.1 eeh 313 1.1 eeh /* 314 1.3 simonb * This routine must be explicitly called to initialize the 315 1.3 simonb * CPU cache information so cache flushe and memcpy operation 316 1.1 eeh * work. 317 1.1 eeh */ 318 1.1 eeh void 319 1.27 cegger cpu_probe_cache(void) 320 1.1 eeh { 321 1.32 matt struct cpu_info * const ci = curcpu(); 322 1.31 matt const struct cputab *cp = models; 323 1.28 kiyohara 324 1.32 matt const u_int pvr = mfpvr(); 325 1.32 matt for (cp = models; cp->name != NULL; cp++) { 326 1.28 kiyohara if ((pvr & cp->mask) == cp->version) 327 1.28 kiyohara break; 328 1.28 kiyohara } 329 1.28 kiyohara 330 1.1 eeh /* 331 1.32 matt * Copy the cache from the cputab into cpu_info. 332 1.1 eeh */ 333 1.32 matt ci->ci_ci = cp->ci; 334 1.1 eeh } 335 1.1 eeh 336 1.1 eeh /* 337 1.1 eeh * These small routines may have to be replaced, 338 1.1 eeh * if/when we support processors other that the 604. 339 1.1 eeh */ 340 1.1 eeh 341 1.1 eeh void 342 1.32 matt dcache_wbinv_page(vaddr_t va) 343 1.1 eeh { 344 1.32 matt const size_t dcache_line_size = curcpu()->ci_ci.dcache_line_size; 345 1.1 eeh 346 1.32 matt if (dcache_line_size) { 347 1.32 matt for (size_t i = 0; i < PAGE_SIZE; i += dcache_line_size) { 348 1.39 rin __asm volatile ("dcbf %0,%1" : : "b" (va), "r" (i)); 349 1.32 matt } 350 1.39 rin __asm volatile ("sync; isync"); 351 1.32 matt } 352 1.1 eeh } 353