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 44 #define ACPI_NOTIFY_CX_STATES 0x81 /* _CST changed. */ 45 46 static int acpi_cpu_probe(device_t dev); 47 static int acpi_cpu_attach(device_t dev); 48 static struct resource_list * 49 acpi_cpu_get_rlist(device_t, device_t); 50 static struct resource * 51 acpi_cpu_alloc_resource(device_t, device_t, 52 int, int *, u_long, u_long, u_long, u_int, int); 53 static int acpi_cpu_release_resource(device_t, device_t, 54 int, int, struct resource *); 55 56 static int acpi_cpu_get_id(uint32_t, uint32_t *, uint32_t *); 57 static void acpi_cpu_notify(ACPI_HANDLE, UINT32, void *); 58 59 static device_method_t acpi_cpu_methods[] = { 60 /* Device interface */ 61 DEVMETHOD(device_probe, acpi_cpu_probe), 62 DEVMETHOD(device_attach, acpi_cpu_attach), 63 DEVMETHOD(device_detach, bus_generic_detach), 64 DEVMETHOD(device_shutdown, bus_generic_shutdown), 65 DEVMETHOD(device_suspend, bus_generic_suspend), 66 DEVMETHOD(device_resume, bus_generic_resume), 67 68 /* Bus interface */ 69 DEVMETHOD(bus_add_child, bus_generic_add_child), 70 DEVMETHOD(bus_print_child, bus_generic_print_child), 71 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), 72 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 73 DEVMETHOD(bus_get_resource_list, acpi_cpu_get_rlist), 74 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 75 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 76 DEVMETHOD(bus_alloc_resource, acpi_cpu_alloc_resource), 77 DEVMETHOD(bus_release_resource, acpi_cpu_release_resource), 78 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 79 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 80 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 81 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 82 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 83 84 DEVMETHOD_END 85 }; 86 87 static driver_t acpi_cpu_driver = { 88 "cpu", 89 acpi_cpu_methods, 90 sizeof(struct acpi_cpu_softc) 91 }; 92 93 static devclass_t acpi_cpu_devclass; 94 DRIVER_MODULE(cpu, acpi, acpi_cpu_driver, acpi_cpu_devclass, NULL, NULL); 95 MODULE_DEPEND(cpu, acpi, 1, 1, 1); 96 97 static int 98 acpi_cpu_probe(device_t dev) 99 { 100 int acpi_id, cpu_id; 101 ACPI_BUFFER buf; 102 ACPI_HANDLE handle; 103 ACPI_STATUS status; 104 ACPI_OBJECT *obj; 105 106 if (acpi_disabled("cpu") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR) 107 return ENXIO; 108 109 handle = acpi_get_handle(dev); 110 111 /* 112 * Get our Processor object. 113 */ 114 buf.Pointer = NULL; 115 buf.Length = ACPI_ALLOCATE_BUFFER; 116 status = AcpiEvaluateObject(handle, NULL, NULL, &buf); 117 if (ACPI_FAILURE(status)) { 118 device_printf(dev, "probe failed to get Processor obj - %s\n", 119 AcpiFormatException(status)); 120 return ENXIO; 121 } 122 123 obj = (ACPI_OBJECT *)buf.Pointer; 124 if (obj->Type != ACPI_TYPE_PROCESSOR) { 125 device_printf(dev, "Processor object has bad type %d\n", obj->Type); 126 AcpiOsFree(obj); 127 return ENXIO; 128 } 129 130 acpi_id = obj->Processor.ProcId; 131 AcpiOsFree(obj); 132 133 /* 134 * Find the processor associated with our unit. We could use the 135 * ProcId as a key, however, some boxes do not have the same values 136 * in their Processor object as the ProcId values in the MADT. 137 */ 138 if (acpi_cpu_get_id(device_get_unit(dev), &acpi_id, &cpu_id) != 0) 139 return ENXIO; 140 141 acpi_set_magic(dev, cpu_id); 142 device_set_desc(dev, "ACPI CPU"); 143 144 return 0; 145 } 146 147 static int 148 acpi_cpu_attach(device_t dev) 149 { 150 struct acpi_cpu_softc *sc = device_get_softc(dev); 151 ACPI_HANDLE handle; 152 device_t child; 153 int cpu_id, cpu_features; 154 struct acpi_softc *acpi_sc; 155 156 handle = acpi_get_handle(dev); 157 cpu_id = acpi_get_magic(dev); 158 159 acpi_sc = acpi_device_get_parent_softc(dev); 160 if (cpu_id == 0) { 161 sysctl_ctx_init(&sc->glob_sysctl_ctx); 162 sc->glob_sysctl_tree = SYSCTL_ADD_NODE(&sc->glob_sysctl_ctx, 163 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 164 OID_AUTO, "cpu", CTLFLAG_RD, 0, 165 "node for CPU global settings"); 166 if (sc->glob_sysctl_tree == NULL) 167 return ENOMEM; 168 } 169 170 sysctl_ctx_init(&sc->pcpu_sysctl_ctx); 171 sc->pcpu_sysctl_tree = SYSCTL_ADD_NODE(&sc->pcpu_sysctl_ctx, 172 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 173 OID_AUTO, device_get_nameunit(dev), CTLFLAG_RD, 0, 174 "node for per-CPU settings"); 175 if (sc->pcpu_sysctl_tree == NULL) { 176 sysctl_ctx_free(&sc->glob_sysctl_ctx); 177 return ENOMEM; 178 } 179 180 /* 181 * Before calling any CPU methods, collect child driver feature hints 182 * and notify ACPI of them. We support unified SMP power control 183 * so advertise this ourselves. Note this is not the same as independent 184 * SMP control where each CPU can have different settings. 185 */ 186 cpu_features = ACPI_PDC_MP_C1PXTX | ACPI_PDC_MP_C2C3; 187 cpu_features |= acpi_cpu_md_features(); 188 189 /* 190 * CPU capabilities are specified as a buffer of 32-bit integers: 191 * revision, count, and one or more capabilities. 192 */ 193 if (cpu_features) { 194 ACPI_OBJECT_LIST arglist; 195 uint32_t cap_set[3]; 196 ACPI_OBJECT arg[4]; 197 ACPI_STATUS status; 198 199 /* UUID needed by _OSC evaluation */ 200 static uint8_t cpu_oscuuid[16] = { 201 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47, 202 0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53 203 }; 204 205 arglist.Pointer = arg; 206 arglist.Count = 4; 207 arg[0].Type = ACPI_TYPE_BUFFER; 208 arg[0].Buffer.Length = sizeof(cpu_oscuuid); 209 arg[0].Buffer.Pointer = cpu_oscuuid; /* UUID */ 210 arg[1].Type = ACPI_TYPE_INTEGER; 211 arg[1].Integer.Value = 1; /* revision */ 212 arg[2].Type = ACPI_TYPE_INTEGER; 213 arg[2].Integer.Value = 2; /* # of capabilities integers */ 214 arg[3].Type = ACPI_TYPE_BUFFER; 215 arg[3].Buffer.Length = sizeof(cap_set[0]) * 2; /* capabilities buffer */ 216 arg[3].Buffer.Pointer = (uint8_t *)cap_set; 217 cap_set[0] = 0; 218 cap_set[1] = cpu_features; 219 status = AcpiEvaluateObject(handle, "_OSC", &arglist, NULL); 220 221 if (!ACPI_SUCCESS(status)) { 222 if (bootverbose) 223 device_printf(dev, "_OSC failed, use _PDC\n"); 224 225 arglist.Pointer = arg; 226 arglist.Count = 1; 227 arg[0].Type = ACPI_TYPE_BUFFER; 228 arg[0].Buffer.Length = sizeof(cap_set); 229 arg[0].Buffer.Pointer = (uint8_t *)cap_set; 230 cap_set[0] = 1; /* revision */ 231 cap_set[1] = 1; /* # of capabilities integers */ 232 cap_set[2] = cpu_features; 233 AcpiEvaluateObject(handle, "_PDC", &arglist, NULL); 234 } 235 } 236 237 child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1); 238 if (child == NULL) 239 return ENXIO; 240 acpi_set_handle(child, handle); 241 acpi_set_magic(child, cpu_id); 242 sc->cpu_cst = child; 243 244 child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1); 245 if (child == NULL) 246 return ENXIO; 247 acpi_set_handle(child, handle); 248 acpi_set_magic(child, cpu_id); 249 250 bus_generic_probe(dev); 251 bus_generic_attach(dev); 252 253 AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc); 254 255 return 0; 256 } 257 258 /* 259 * All resources are assigned directly to us by acpi, 260 * so 'child' is bypassed here. 261 */ 262 static struct resource_list * 263 acpi_cpu_get_rlist(device_t dev, device_t child __unused) 264 { 265 return BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 266 } 267 268 static struct resource * 269 acpi_cpu_alloc_resource(device_t dev, device_t child __unused, 270 int type, int *rid, u_long start, u_long end, 271 u_long count, u_int flags, int cpuid) 272 { 273 return BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid, 274 start, end, count, flags, cpuid); 275 } 276 277 static int 278 acpi_cpu_release_resource(device_t dev, device_t child __unused, 279 int type, int rid, struct resource *r) 280 { 281 return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type, rid, r); 282 } 283 284 /* 285 * Find the nth present CPU and return its pc_cpuid as well as set the 286 * pc_acpi_id from the most reliable source. 287 */ 288 static int 289 acpi_cpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id) 290 { 291 struct mdglobaldata *md; 292 uint32_t i; 293 294 KASSERT(acpi_id != NULL, ("Null acpi_id")); 295 KASSERT(cpu_id != NULL, ("Null cpu_id")); 296 for (i = 0; i < ncpus; i++) { 297 if ((smp_active_mask & CPUMASK(i)) == 0) 298 continue; 299 md = (struct mdglobaldata *)globaldata_find(i); 300 KASSERT(md != NULL, ("no pcpu data for %d", i)); 301 if (idx-- == 0) { 302 /* 303 * If pc_acpi_id was not initialized (e.g., a non-APIC UP box) 304 * override it with the value from the ASL. Otherwise, if the 305 * two don't match, prefer the MADT-derived value. Finally, 306 * return the pc_cpuid to reference this processor. 307 */ 308 if (md->gd_acpi_id == 0xffffffff) 309 md->gd_acpi_id = *acpi_id; 310 else if (md->gd_acpi_id != *acpi_id) 311 *acpi_id = md->gd_acpi_id; 312 *cpu_id = md->mi.gd_cpuid; 313 return 0; 314 } 315 } 316 return ESRCH; 317 } 318 319 static void 320 acpi_cpu_notify(ACPI_HANDLE handler __unused, UINT32 notify, void *xsc) 321 { 322 struct acpi_cpu_softc *sc = xsc; 323 324 switch (notify) { 325 case ACPI_NOTIFY_CX_STATES: 326 if (sc->cpu_cst_notify != NULL) 327 sc->cpu_cst_notify(sc->cpu_cst); 328 break; 329 } 330 } 331