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