kernel/acpi: Print any errors returned by CPU capability setting using _OSC.
[dragonfly.git] / sys / dev / acpica / acpi_cpu.c
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         if (ACPI_SUCCESS(status)) {
221             if (cap_set[0] & ACPI_OSCERR_OSCFAIL)
222                 device_printf(dev, "_OSC unable to process request\n");
223             if (cap_set[0] & ACPI_OSCERR_UUID)
224                 device_printf(dev, "_OSC unrecognized UUID\n");
225             if (cap_set[0] & ACPI_OSCERR_REVISION)
226                 device_printf(dev, "_OSC unrecognized revision ID\n");
227             if (cap_set[0] & ACPI_OSCERR_CAPSMASKED)
228                 device_printf(dev, "_OSC capabilities have been masked: %#x\n",
229                     cpu_features & ~cap_set[1]);
230         } else {
231             if (bootverbose)
232                 device_printf(dev, "_OSC failed, using _PDC\n");
233
234             arglist.Pointer = arg;
235             arglist.Count = 1;
236             arg[0].Type = ACPI_TYPE_BUFFER;
237             arg[0].Buffer.Length = sizeof(cap_set);
238             arg[0].Buffer.Pointer = (uint8_t *)cap_set;
239             cap_set[0] = 1; /* revision */
240             cap_set[1] = 1; /* # of capabilities integers */
241             cap_set[2] = cpu_features;
242             AcpiEvaluateObject(handle, "_PDC", &arglist, NULL);
243         }
244     }
245
246     child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1);
247     if (child == NULL)
248         return ENXIO;
249     acpi_set_handle(child, handle);
250     acpi_set_magic(child, cpu_id);
251     sc->cpu_cst = child;
252
253     child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1);
254     if (child == NULL)
255         return ENXIO;
256     acpi_set_handle(child, handle);
257     acpi_set_magic(child, cpu_id);
258
259     bus_generic_probe(dev);
260     bus_generic_attach(dev);
261
262     AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc);
263
264     return 0;
265 }
266
267 /*
268  * All resources are assigned directly to us by acpi,
269  * so 'child' is bypassed here.
270  */
271 static struct resource_list *
272 acpi_cpu_get_rlist(device_t dev, device_t child __unused)
273 {
274     return BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
275 }
276
277 static struct resource *
278 acpi_cpu_alloc_resource(device_t dev, device_t child __unused,
279                         int type, int *rid, u_long start, u_long end,
280                         u_long count, u_int flags, int cpuid)
281 {
282     return BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid,
283                               start, end, count, flags, cpuid);
284 }
285
286 static int
287 acpi_cpu_release_resource(device_t dev, device_t child __unused,
288                           int type, int rid, struct resource *r)
289 {
290     return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type, rid, r);
291 }
292
293 /*
294  * Find the nth present CPU and return its pc_cpuid as well as set the
295  * pc_acpi_id from the most reliable source.
296  */
297 static int
298 acpi_cpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id)
299 {
300     struct mdglobaldata *md;
301     uint32_t i;
302
303     KASSERT(acpi_id != NULL, ("Null acpi_id"));
304     KASSERT(cpu_id != NULL, ("Null cpu_id"));
305     for (i = 0; i < ncpus; i++) {
306         if ((smp_active_mask & CPUMASK(i)) == 0)
307             continue;
308         md = (struct mdglobaldata *)globaldata_find(i);
309         KASSERT(md != NULL, ("no pcpu data for %d", i));
310         if (idx-- == 0) {
311             /*
312              * If pc_acpi_id was not initialized (e.g., a non-APIC UP box)
313              * override it with the value from the ASL.  Otherwise, if the
314              * two don't match, prefer the MADT-derived value.  Finally,
315              * return the pc_cpuid to reference this processor.
316              */
317             if (md->gd_acpi_id == 0xffffffff)
318                 md->gd_acpi_id = *acpi_id;
319             else if (md->gd_acpi_id != *acpi_id)
320                 *acpi_id = md->gd_acpi_id;
321             *cpu_id = md->mi.gd_cpuid;
322             return 0;
323         }
324     }
325     return ESRCH;
326 }
327
328 static void
329 acpi_cpu_notify(ACPI_HANDLE handler __unused, UINT32 notify, void *xsc)
330 {
331     struct acpi_cpu_softc *sc = xsc;
332
333     switch (notify) {
334     case ACPI_NOTIFY_CX_STATES:
335         if (sc->cpu_cst_notify != NULL)
336             sc->cpu_cst_notify(sc->cpu_cst);
337         break;
338     }
339 }