1 /*- 2 * Copyright (c) 2003-2005 Nate Lawson (SDG) 3 * Copyright (c) 2001 Michael Smith 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: src/sys/dev/acpica/acpi_cpu.c,v 1.72 2008/04/12 12:06:00 rpaulo Exp $ 28 */ 29 30 #include "opt_acpi.h" 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/kernel.h> 35 #include <sys/sysctl.h> 36 37 #include <machine/globaldata.h> 38 #include <machine/smp.h> 39 40 #include "acpi.h" 41 #include "acpivar.h" 42 #include "acpi_cpu.h" 43 #include "cpu_if.h" 44 45 #define ACPI_NOTIFY_PX_STATES 0x80 /* _PPC/_PDL changed. */ 46 #define ACPI_NOTIFY_CX_STATES 0x81 /* _CST changed. */ 47 48 static int acpi_cpu_probe(device_t dev); 49 static int acpi_cpu_attach(device_t dev); 50 static struct resource_list * 51 acpi_cpu_get_rlist(device_t, device_t); 52 static struct resource * 53 acpi_cpu_alloc_resource(device_t, device_t, 54 int, int *, u_long, u_long, u_long, u_int, int); 55 static int acpi_cpu_release_resource(device_t, device_t, 56 int, int, struct resource *); 57 static struct ksensordev * 58 acpi_cpu_get_sensdev(device_t); 59 60 static int acpi_cpu_get_id(uint32_t, uint32_t *, uint32_t *); 61 static void acpi_cpu_notify(ACPI_HANDLE, UINT32, void *); 62 63 static device_method_t acpi_cpu_methods[] = { 64 /* Device interface */ 65 DEVMETHOD(device_probe, acpi_cpu_probe), 66 DEVMETHOD(device_attach, acpi_cpu_attach), 67 DEVMETHOD(device_detach, bus_generic_detach), 68 DEVMETHOD(device_shutdown, bus_generic_shutdown), 69 DEVMETHOD(device_suspend, bus_generic_suspend), 70 DEVMETHOD(device_resume, bus_generic_resume), 71 72 /* Bus interface */ 73 DEVMETHOD(bus_add_child, bus_generic_add_child), 74 DEVMETHOD(bus_print_child, bus_generic_print_child), 75 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), 76 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 77 DEVMETHOD(bus_get_resource_list, acpi_cpu_get_rlist), 78 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 79 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 80 DEVMETHOD(bus_alloc_resource, acpi_cpu_alloc_resource), 81 DEVMETHOD(bus_release_resource, acpi_cpu_release_resource), 82 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 83 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 84 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 85 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 86 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 87 88 /* CPU interface */ 89 DEVMETHOD(cpu_get_sensdev, acpi_cpu_get_sensdev), 90 91 DEVMETHOD_END 92 }; 93 94 static driver_t acpi_cpu_driver = { 95 "cpu", 96 acpi_cpu_methods, 97 sizeof(struct acpi_cpu_softc), 98 .gpri = KOBJ_GPRI_ACPI+2 99 }; 100 101 static devclass_t acpi_cpu_devclass; 102 DRIVER_MODULE(cpu, acpi, acpi_cpu_driver, acpi_cpu_devclass, NULL, NULL); 103 MODULE_DEPEND(cpu, acpi, 1, 1, 1); 104 105 static int 106 acpi_cpu_probe(device_t dev) 107 { 108 int acpi_id, cpu_id; 109 ACPI_BUFFER buf; 110 ACPI_HANDLE handle; 111 ACPI_STATUS status; 112 ACPI_OBJECT *obj; 113 114 if (acpi_disabled("cpu") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR) 115 return ENXIO; 116 117 handle = acpi_get_handle(dev); 118 119 /* 120 * Get our Processor object. 121 */ 122 buf.Pointer = NULL; 123 buf.Length = ACPI_ALLOCATE_BUFFER; 124 status = AcpiEvaluateObject(handle, NULL, NULL, &buf); 125 if (ACPI_FAILURE(status)) { 126 device_printf(dev, "probe failed to get Processor obj - %s\n", 127 AcpiFormatException(status)); 128 return ENXIO; 129 } 130 131 obj = (ACPI_OBJECT *)buf.Pointer; 132 if (obj->Type != ACPI_TYPE_PROCESSOR) { 133 device_printf(dev, "Processor object has bad type %d\n", obj->Type); 134 AcpiOsFree(obj); 135 return ENXIO; 136 } 137 138 acpi_id = obj->Processor.ProcId; 139 AcpiOsFree(obj); 140 141 /* 142 * Find the processor associated with our unit. We could use the 143 * ProcId as a key, however, some boxes do not have the same values 144 * in their Processor object as the ProcId values in the MADT. 145 */ 146 if (acpi_cpu_get_id(device_get_unit(dev), &acpi_id, &cpu_id) != 0) 147 return ENXIO; 148 149 acpi_set_magic(dev, cpu_id); 150 device_set_desc(dev, "ACPI CPU"); 151 152 return 0; 153 } 154 155 static int 156 acpi_cpu_attach(device_t dev) 157 { 158 struct acpi_cpu_softc *sc = device_get_softc(dev); 159 ACPI_HANDLE handle; 160 device_t child; 161 int cpu_id, cpu_features; 162 struct acpi_softc *acpi_sc; 163 164 sc->cpu_dev = dev; 165 166 handle = acpi_get_handle(dev); 167 cpu_id = acpi_get_magic(dev); 168 169 acpi_sc = acpi_device_get_parent_softc(dev); 170 if (cpu_id == 0) { 171 sysctl_ctx_init(&sc->glob_sysctl_ctx); 172 sc->glob_sysctl_tree = SYSCTL_ADD_NODE(&sc->glob_sysctl_ctx, 173 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 174 OID_AUTO, "cpu", CTLFLAG_RD, 0, 175 "node for CPU global settings"); 176 if (sc->glob_sysctl_tree == NULL) 177 return ENOMEM; 178 } 179 180 sysctl_ctx_init(&sc->pcpu_sysctl_ctx); 181 sc->pcpu_sysctl_tree = SYSCTL_ADD_NODE(&sc->pcpu_sysctl_ctx, 182 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 183 OID_AUTO, device_get_nameunit(dev), CTLFLAG_RD, 0, 184 "node for per-CPU settings"); 185 if (sc->pcpu_sysctl_tree == NULL) { 186 sysctl_ctx_free(&sc->glob_sysctl_ctx); 187 return ENOMEM; 188 } 189 190 /* 191 * Before calling any CPU methods, collect child driver feature hints 192 * and notify ACPI of them. We support unified SMP power control 193 * so advertise this ourselves. Note this is not the same as independent 194 * SMP control where each CPU can have different settings. 195 */ 196 cpu_features = ACPI_PDC_MP_C1PXTX | ACPI_PDC_MP_C2C3; 197 cpu_features |= acpi_cpu_md_features(); 198 199 /* 200 * CPU capabilities are specified as a buffer of 32-bit integers: 201 * revision, count, and one or more capabilities. 202 */ 203 if (cpu_features) { 204 uint32_t cap_set[3]; 205 ACPI_STATUS status; 206 207 cap_set[0] = 0; 208 cap_set[1] = cpu_features; 209 status = acpi_eval_osc(dev, handle, 210 "4077A616-290C-47BE-9EBD-D87058713953", 1, cap_set, 2); 211 212 if (ACPI_FAILURE(status)) { 213 ACPI_OBJECT_LIST arglist; 214 ACPI_OBJECT arg[4]; 215 216 if (bootverbose) 217 device_printf(dev, "_OSC failed, using _PDC\n"); 218 219 arglist.Pointer = arg; 220 arglist.Count = 1; 221 arg[0].Type = ACPI_TYPE_BUFFER; 222 arg[0].Buffer.Length = sizeof(cap_set); 223 arg[0].Buffer.Pointer = (uint8_t *)cap_set; 224 cap_set[0] = 1; /* revision */ 225 cap_set[1] = 1; /* # of capabilities integers */ 226 cap_set[2] = cpu_features; 227 AcpiEvaluateObject(handle, "_PDC", &arglist, NULL); 228 } 229 } 230 231 ksnprintf(sc->cpu_sensdev.xname, sizeof(sc->cpu_sensdev.xname), "%s", 232 device_get_nameunit(dev)); 233 sensordev_install(&sc->cpu_sensdev); 234 235 child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1); 236 if (child == NULL) 237 return ENXIO; 238 acpi_set_handle(child, handle); 239 acpi_set_magic(child, cpu_id); 240 sc->cpu_cst = child; 241 242 child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1); 243 if (child == NULL) 244 return ENXIO; 245 acpi_set_handle(child, handle); 246 acpi_set_magic(child, cpu_id); 247 sc->cpu_pst = child; 248 249 bus_generic_probe(dev); 250 bus_generic_attach(dev); 251 252 AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc); 253 254 return 0; 255 } 256 257 /* 258 * All resources are assigned directly to us by acpi, 259 * so 'child' is bypassed here. 260 */ 261 static struct resource_list * 262 acpi_cpu_get_rlist(device_t dev, device_t child __unused) 263 { 264 return BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 265 } 266 267 static struct resource * 268 acpi_cpu_alloc_resource(device_t dev, device_t child __unused, 269 int type, int *rid, u_long start, u_long end, 270 u_long count, u_int flags, int cpuid) 271 { 272 return BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid, 273 start, end, count, flags, cpuid); 274 } 275 276 static int 277 acpi_cpu_release_resource(device_t dev, device_t child __unused, 278 int type, int rid, struct resource *r) 279 { 280 return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type, rid, r); 281 } 282 283 /* 284 * Find the nth present CPU and return its pc_cpuid as well as set the 285 * pc_acpi_id from the most reliable source. 286 */ 287 static int 288 acpi_cpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id) 289 { 290 struct mdglobaldata *md; 291 uint32_t i; 292 293 KASSERT(acpi_id != NULL, ("Null acpi_id")); 294 KASSERT(cpu_id != NULL, ("Null cpu_id")); 295 for (i = 0; i < ncpus; i++) { 296 if (CPUMASK_TESTBIT(smp_active_mask, i) == 0) 297 continue; 298 md = (struct mdglobaldata *)globaldata_find(i); 299 KASSERT(md != NULL, ("no pcpu data for %d", i)); 300 if (idx-- == 0) { 301 /* 302 * If gd_acpi_id was not initialized (e.g., box w/o MADT) 303 * override it with the value from the ASL. Otherwise, if the 304 * two don't match, prefer the MADT-derived value. Finally, 305 * return the gd_cpuid to reference this processor. 306 */ 307 if (md->gd_acpi_id == 0xffffffff) { 308 kprintf("cpu%d: acpi id was not set, set it to %u\n", 309 i, *acpi_id); 310 md->gd_acpi_id = *acpi_id; 311 } else if (md->gd_acpi_id != *acpi_id) { 312 kprintf("cpu%d: acpi id mismatch, madt %u, " 313 "processor object %u\n", 314 i, md->gd_acpi_id, *acpi_id); 315 *acpi_id = md->gd_acpi_id; 316 } 317 *cpu_id = md->mi.gd_cpuid; 318 return 0; 319 } 320 } 321 return ESRCH; 322 } 323 324 static void 325 acpi_cpu_notify(ACPI_HANDLE handle __unused, UINT32 notify, void *xsc) 326 { 327 struct acpi_cpu_softc *sc = xsc; 328 329 switch (notify) { 330 case ACPI_NOTIFY_CX_STATES: 331 if (sc->cpu_cst_notify != NULL) 332 sc->cpu_cst_notify(sc->cpu_cst); 333 break; 334 case ACPI_NOTIFY_PX_STATES: 335 if (sc->cpu_pst_notify != NULL) 336 sc->cpu_pst_notify(sc->cpu_pst); 337 break; 338 default: 339 device_printf(sc->cpu_dev, "unknown notify: %#x\n", notify); 340 break; 341 } 342 } 343 344 static struct ksensordev * 345 acpi_cpu_get_sensdev(device_t dev) 346 { 347 struct acpi_cpu_softc *sc = device_get_softc(dev); 348 349 return &sc->cpu_sensdev; 350 } 351