1 /* $NetBSD: cpu.c,v 1.17 2025/08/31 19:10:00 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 2006 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * 8 * Author: 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 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.17 2025/08/31 19:10:00 rillig Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/cpu.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 #include <sys/device.h> 40 #include <sys/kmem.h> 41 42 #include <dev/acpi/acpica.h> 43 #include <dev/acpi/acpivar.h> 44 45 #define MHz 1000000L 46 #define GHz (1000L * MHz) 47 48 extern int ia64_sync_icache_needed; 49 50 struct cpu_info cpu_info_primary __aligned(CACHE_LINE_SIZE); 51 struct cpu_info *cpu_info_list = &cpu_info_primary; 52 53 struct cpu_softc { 54 device_t sc_dev; /* device tree glue */ 55 struct cpu_info *sc_info; /* pointer to CPU info */ 56 }; 57 58 static int cpu_match(device_t, cfdata_t, void *); 59 static void cpu_attach(device_t, device_t, void *); 60 61 static void identifycpu(struct cpu_softc *); 62 63 CFATTACH_DECL_NEW(cpu, sizeof(struct cpu_softc), 64 cpu_match, cpu_attach, NULL, NULL); 65 66 67 static int 68 cpu_match(device_t parent, cfdata_t match, void *aux) 69 { 70 71 return 1; 72 } 73 74 static void 75 cpu_attach(device_t parent, device_t self, void *aux) 76 { 77 struct cpu_softc *sc = device_private(self); 78 ACPI_MADT_LOCAL_SAPIC *sapic = (ACPI_MADT_LOCAL_SAPIC *)aux; 79 struct cpu_info *ci; 80 uint64_t lid; 81 int id, eid; 82 83 aprint_naive("\n"); 84 aprint_normal(": ProcessorID %d, Id %d, Eid %d%s\n", 85 sapic->ProcessorId, sapic->Id, sapic->Eid, 86 sapic->LapicFlags & ACPI_MADT_ENABLED ? "" : " (disabled)"); 87 88 /* Get current CPU Id */ 89 lid = ia64_get_lid(); 90 id = (lid & 0x00000000ff000000) >> 24; 91 eid = (lid & 0x0000000000ff0000) >> 16; 92 93 sc->sc_dev = self; 94 if (id == sapic->Id && eid == sapic->Eid) 95 ci = curcpu(); 96 else { 97 ci = (struct cpu_info *)kmem_zalloc(sizeof(*ci), KM_SLEEP); 98 } 99 sc->sc_info = ci; 100 101 ci->ci_cpuid = sapic->ProcessorId; 102 ci->ci_intrdepth = -1; /* need ? */ 103 ci->ci_dev = self; 104 105 identifycpu(sc); 106 107 return; 108 } 109 110 111 static void 112 identifycpu(struct cpu_softc *sc) 113 { 114 uint64_t vendor[3]; 115 const char *family_name, *model_name; 116 uint64_t features, tmp; 117 int revision, model, family; 118 char bitbuf[32]; 119 extern uint64_t processor_frequency; 120 121 /* 122 * Assumes little-endian. 123 */ 124 vendor[0] = ia64_get_cpuid(0); 125 vendor[1] = ia64_get_cpuid(1); 126 vendor[2] = '\0'; 127 128 tmp = ia64_get_cpuid(3); 129 /* number = (tmp >> 0) & 0xff; */ 130 revision = (tmp >> 8) & 0xff; 131 model = (tmp >> 16) & 0xff; 132 family = (tmp >> 24) & 0xff; 133 /* archrev = (tmp >> 32) & 0xff; */ 134 135 family_name = model_name = "unknown"; 136 switch (family) { 137 case 0x07: 138 family_name = "Itanium"; 139 model_name = "Merced"; 140 break; 141 case 0x1f: 142 family_name = "Itanium 2"; 143 switch (model) { 144 case 0x00: 145 model_name = "McKinley"; 146 break; 147 case 0x01: 148 /* 149 * Deerfield is a low-voltage variant based on the 150 * Madison core. We need circumstantial evidence 151 * (i.e. the clock frequency) to identify those. 152 * Allow for roughly 1% error margin. 153 */ 154 tmp = processor_frequency >> 7; 155 if ((processor_frequency - tmp) < 1*GHz && 156 (processor_frequency + tmp) >= 1*GHz) 157 model_name = "Deerfield"; 158 else 159 model_name = "Madison"; 160 break; 161 case 0x02: 162 model_name = "Madison II"; 163 break; 164 } 165 break; 166 case 0x20: 167 ia64_sync_icache_needed = 1; 168 169 family_name = "Itanium 2"; 170 switch (model) { 171 case 0x00: 172 model_name = "Montecito"; 173 break; 174 case 0x01: 175 model_name = "Montvale"; 176 break; 177 } 178 break; 179 } 180 cpu_setmodel("%s", model_name); 181 182 features = ia64_get_cpuid(4); 183 184 aprint_normal_dev(sc->sc_dev, "%s (", model_name); 185 if (processor_frequency) { 186 aprint_normal("%ld.%02ld-MHz ", 187 (processor_frequency + 4999) / MHz, 188 ((processor_frequency + 4999) / (MHz/100)) % 100); 189 } 190 aprint_normal("%s)\n", family_name); 191 aprint_normal_dev(sc->sc_dev, "Origin \"%s\", Revision %d\n", 192 (char *)vendor, revision); 193 194 #define IA64_FEATURES_BITMASK "\177\020" \ 195 "b\0LB\0" /* 'brl' instruction is implemented */ \ 196 "b\1SD\0" /* Processor implements spontaneous deferral */ \ 197 "b\2AO\0" /* Processor implements 16-byte atomic operations */ \ 198 "\0" 199 snprintb(bitbuf, sizeof(bitbuf), IA64_FEATURES_BITMASK, features); 200 aprint_normal_dev(sc->sc_dev, "Features %s\n", bitbuf); 201 } 202