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
acpi_cpu_probe(device_t dev)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
acpi_cpu_attach(device_t dev)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 *
acpi_cpu_get_rlist(device_t dev,device_t child __unused)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 *
acpi_cpu_alloc_resource(device_t dev,device_t child __unused,int type,int * rid,u_long start,u_long end,u_long count,u_int flags,int cpuid)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
acpi_cpu_release_resource(device_t dev,device_t child __unused,int type,int rid,struct resource * r)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
acpi_cpu_get_id(uint32_t idx,uint32_t * acpi_id,uint32_t * cpu_id)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
acpi_cpu_notify(ACPI_HANDLE handle __unused,UINT32 notify,void * xsc)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 *
acpi_cpu_get_sensdev(device_t dev)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