acpi_cpu: Split C-State support out of cpu driver.
[dragonfly.git] / sys / dev / acpica5 / 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  * $DragonFly: src/sys/dev/acpica5/acpi_cpu.c,v 1.21 2008/09/05 10:28:35 hasso Exp $
29  */
30
31 #include "opt_acpi.h"
32
33 #include <sys/param.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/sysctl.h>
37
38 #include <machine/globaldata.h>
39 #include <machine/smp.h>
40
41 #include "acpi.h"
42 #include "acpivar.h"
43 #include "acpi_cpu.h"
44
45 static int      acpi_cpu_probe(device_t dev);
46 static int      acpi_cpu_attach(device_t dev);
47
48 static int      acpi_cpu_get_id(uint32_t, uint32_t *, uint32_t *);
49
50 static device_method_t acpi_cpu_methods[] = {
51     /* Device interface */
52     DEVMETHOD(device_probe,             acpi_cpu_probe),
53     DEVMETHOD(device_attach,            acpi_cpu_attach),
54     DEVMETHOD(device_shutdown,          bus_generic_shutdown),
55     DEVMETHOD(device_detach,            bus_generic_detach),
56     DEVMETHOD(device_suspend,           bus_generic_suspend),
57     DEVMETHOD(device_resume,            bus_generic_resume),
58
59     /* Bus interface */
60     DEVMETHOD(bus_add_child,            bus_generic_add_child),
61     DEVMETHOD(bus_print_child,          bus_generic_print_child),
62     DEVMETHOD(bus_read_ivar,            bus_generic_read_ivar),
63     DEVMETHOD(bus_write_ivar,           bus_generic_write_ivar),
64     DEVMETHOD(bus_get_resource_list,    bus_generic_get_resource_list),
65     DEVMETHOD(bus_set_resource,         bus_generic_rl_set_resource),
66     DEVMETHOD(bus_get_resource,         bus_generic_rl_get_resource),
67     DEVMETHOD(bus_alloc_resource,       bus_generic_alloc_resource),
68     DEVMETHOD(bus_release_resource,     bus_generic_release_resource),
69     DEVMETHOD(bus_driver_added,         bus_generic_driver_added),
70     DEVMETHOD(bus_activate_resource,    bus_generic_activate_resource),
71     DEVMETHOD(bus_deactivate_resource,  bus_generic_deactivate_resource),
72     DEVMETHOD(bus_setup_intr,           bus_generic_setup_intr),
73     DEVMETHOD(bus_teardown_intr,        bus_generic_teardown_intr),
74     { 0, 0 }
75 };
76
77 static driver_t acpi_cpu_driver = {
78     "cpu",
79     acpi_cpu_methods,
80     sizeof(struct acpi_cpux_softc)
81 };
82
83 static devclass_t acpi_cpu_devclass;
84 DRIVER_MODULE(cpu, acpi, acpi_cpu_driver, acpi_cpu_devclass, 0, 0);
85 MODULE_DEPEND(cpu, acpi, 1, 1, 1);
86
87 static int
88 acpi_cpu_probe(device_t dev)
89 {
90     int acpi_id, cpu_id;
91     ACPI_BUFFER buf;
92     ACPI_HANDLE handle;
93     ACPI_STATUS status;
94     ACPI_OBJECT *obj;
95
96     if (acpi_disabled("cpu") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
97         return ENXIO;
98
99     handle = acpi_get_handle(dev);
100
101     /*
102      * Get our Processor object.
103      */
104     buf.Pointer = NULL;
105     buf.Length = ACPI_ALLOCATE_BUFFER;
106     status = AcpiEvaluateObject(handle, NULL, NULL, &buf);
107     if (ACPI_FAILURE(status)) {
108         device_printf(dev, "probe failed to get Processor obj - %s\n",
109                       AcpiFormatException(status));
110         return ENXIO;
111     }
112
113     obj = (ACPI_OBJECT *)buf.Pointer;
114     if (obj->Type != ACPI_TYPE_PROCESSOR) {
115         device_printf(dev, "Processor object has bad type %d\n", obj->Type);
116         AcpiOsFree(obj);
117         return ENXIO;
118     }
119
120     acpi_id = obj->Processor.ProcId;
121     AcpiOsFree(obj);
122
123     /*
124      * Find the processor associated with our unit.  We could use the
125      * ProcId as a key, however, some boxes do not have the same values
126      * in their Processor object as the ProcId values in the MADT.
127      */
128     if (acpi_cpu_get_id(device_get_unit(dev), &acpi_id, &cpu_id) != 0)
129         return ENXIO;
130
131     acpi_set_magic(dev, cpu_id);
132     device_set_desc(dev, "ACPI CPU");
133
134     return 0;
135 }
136
137 static int
138 acpi_cpu_attach(device_t dev)
139 {
140     struct acpi_cpux_softc *sc = device_get_softc(dev);
141     ACPI_HANDLE handle;
142     device_t child;
143     int cpu_id;
144     struct acpi_softc *acpi_sc;
145
146     handle = acpi_get_handle(dev);
147     cpu_id = acpi_get_magic(dev);
148
149     acpi_sc = acpi_device_get_parent_softc(dev);
150     if (cpu_id == 0) {
151         sysctl_ctx_init(&sc->glob_sysctl_ctx);
152         sc->glob_sysctl_tree = SYSCTL_ADD_NODE(&sc->glob_sysctl_ctx,
153                                SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
154                                OID_AUTO, "cpu", CTLFLAG_RD, 0,
155                                "node for CPU global settings");
156         if (sc->glob_sysctl_tree == NULL)
157             return ENOMEM;
158     }
159
160     sysctl_ctx_init(&sc->pcpu_sysctl_ctx);
161     sc->pcpu_sysctl_tree = SYSCTL_ADD_NODE(&sc->pcpu_sysctl_ctx,
162                            SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
163                            OID_AUTO, device_get_nameunit(dev), CTLFLAG_RD, 0,
164                            "node for per-CPU settings");
165     if (sc->pcpu_sysctl_tree == NULL) {
166         sysctl_ctx_free(&sc->glob_sysctl_ctx);
167         return ENOMEM;
168     }
169
170     child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1);
171     if (child == NULL)
172         return ENXIO;
173
174     acpi_set_handle(child, handle);
175     acpi_set_magic(child, cpu_id);
176
177     bus_generic_attach(dev);
178
179     return 0;
180 }
181
182 /*
183  * Find the nth present CPU and return its pc_cpuid as well as set the
184  * pc_acpi_id from the most reliable source.
185  */
186 static int
187 acpi_cpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id)
188 {
189     struct mdglobaldata *md;
190     uint32_t i;
191
192     KASSERT(acpi_id != NULL, ("Null acpi_id"));
193     KASSERT(cpu_id != NULL, ("Null cpu_id"));
194     for (i = 0; i < ncpus; i++) {
195         if ((smp_active_mask & (1 << i)) == 0)
196             continue;
197         md = (struct mdglobaldata *)globaldata_find(i);
198         KASSERT(md != NULL, ("no pcpu data for %d", i));
199         if (idx-- == 0) {
200             /*
201              * If pc_acpi_id was not initialized (e.g., a non-APIC UP box)
202              * override it with the value from the ASL.  Otherwise, if the
203              * two don't match, prefer the MADT-derived value.  Finally,
204              * return the pc_cpuid to reference this processor.
205              */
206             if (md->gd_acpi_id == 0xffffffff)
207                 md->gd_acpi_id = *acpi_id;
208             else if (md->gd_acpi_id != *acpi_id)
209                 *acpi_id = md->gd_acpi_id;
210             *cpu_id = md->mi.gd_cpuid;
211             return 0;
212         }
213     }
214     return ESRCH;
215 }