2 * Copyright (c) 2003-2005 Nate Lawson (SDG)
3 * Copyright (c) 2001 Michael Smith
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
27 * $FreeBSD: src/sys/dev/acpica/acpi_cpu.c,v 1.72 2008/04/12 12:06:00 rpaulo Exp $
32 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/sysctl.h>
37 #include <machine/globaldata.h>
38 #include <machine/smp.h>
45 #define ACPI_NOTIFY_PX_STATES 0x80 /* _PPC/_PDL changed. */
46 #define ACPI_NOTIFY_CX_STATES 0x81 /* _CST changed. */
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
);
60 static int acpi_cpu_get_id(uint32_t, uint32_t *, uint32_t *);
61 static void acpi_cpu_notify(ACPI_HANDLE
, UINT32
, void *);
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
),
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
),
89 DEVMETHOD(cpu_get_sensdev
, acpi_cpu_get_sensdev
),
94 static driver_t acpi_cpu_driver
= {
97 sizeof(struct acpi_cpu_softc
)
100 static devclass_t acpi_cpu_devclass
;
101 DRIVER_MODULE(cpu
, acpi
, acpi_cpu_driver
, acpi_cpu_devclass
, NULL
, NULL
);
102 MODULE_DEPEND(cpu
, acpi
, 1, 1, 1);
105 acpi_cpu_probe(device_t dev
)
113 if (acpi_disabled("cpu") || acpi_get_type(dev
) != ACPI_TYPE_PROCESSOR
)
116 handle
= acpi_get_handle(dev
);
119 * Get our Processor object.
122 buf
.Length
= ACPI_ALLOCATE_BUFFER
;
123 status
= AcpiEvaluateObject(handle
, NULL
, NULL
, &buf
);
124 if (ACPI_FAILURE(status
)) {
125 device_printf(dev
, "probe failed to get Processor obj - %s\n",
126 AcpiFormatException(status
));
130 obj
= (ACPI_OBJECT
*)buf
.Pointer
;
131 if (obj
->Type
!= ACPI_TYPE_PROCESSOR
) {
132 device_printf(dev
, "Processor object has bad type %d\n", obj
->Type
);
137 acpi_id
= obj
->Processor
.ProcId
;
141 * Find the processor associated with our unit. We could use the
142 * ProcId as a key, however, some boxes do not have the same values
143 * in their Processor object as the ProcId values in the MADT.
145 if (acpi_cpu_get_id(device_get_unit(dev
), &acpi_id
, &cpu_id
) != 0)
148 acpi_set_magic(dev
, cpu_id
);
149 device_set_desc(dev
, "ACPI CPU");
155 acpi_cpu_attach(device_t dev
)
157 struct acpi_cpu_softc
*sc
= device_get_softc(dev
);
160 int cpu_id
, cpu_features
;
161 struct acpi_softc
*acpi_sc
;
165 handle
= acpi_get_handle(dev
);
166 cpu_id
= acpi_get_magic(dev
);
168 acpi_sc
= acpi_device_get_parent_softc(dev
);
170 sysctl_ctx_init(&sc
->glob_sysctl_ctx
);
171 sc
->glob_sysctl_tree
= SYSCTL_ADD_NODE(&sc
->glob_sysctl_ctx
,
172 SYSCTL_CHILDREN(acpi_sc
->acpi_sysctl_tree
),
173 OID_AUTO
, "cpu", CTLFLAG_RD
, 0,
174 "node for CPU global settings");
175 if (sc
->glob_sysctl_tree
== NULL
)
179 sysctl_ctx_init(&sc
->pcpu_sysctl_ctx
);
180 sc
->pcpu_sysctl_tree
= SYSCTL_ADD_NODE(&sc
->pcpu_sysctl_ctx
,
181 SYSCTL_CHILDREN(acpi_sc
->acpi_sysctl_tree
),
182 OID_AUTO
, device_get_nameunit(dev
), CTLFLAG_RD
, 0,
183 "node for per-CPU settings");
184 if (sc
->pcpu_sysctl_tree
== NULL
) {
185 sysctl_ctx_free(&sc
->glob_sysctl_ctx
);
190 * Before calling any CPU methods, collect child driver feature hints
191 * and notify ACPI of them. We support unified SMP power control
192 * so advertise this ourselves. Note this is not the same as independent
193 * SMP control where each CPU can have different settings.
195 cpu_features
= ACPI_PDC_MP_C1PXTX
| ACPI_PDC_MP_C2C3
;
196 cpu_features
|= acpi_cpu_md_features();
199 * CPU capabilities are specified as a buffer of 32-bit integers:
200 * revision, count, and one or more capabilities.
207 cap_set
[1] = cpu_features
;
208 status
= acpi_eval_osc(dev
, handle
,
209 "4077A616-290C-47BE-9EBD-D87058713953", 1, cap_set
, 2);
211 if (ACPI_FAILURE(status
)) {
212 ACPI_OBJECT_LIST arglist
;
216 device_printf(dev
, "_OSC failed, using _PDC\n");
218 arglist
.Pointer
= arg
;
220 arg
[0].Type
= ACPI_TYPE_BUFFER
;
221 arg
[0].Buffer
.Length
= sizeof(cap_set
);
222 arg
[0].Buffer
.Pointer
= (uint8_t *)cap_set
;
223 cap_set
[0] = 1; /* revision */
224 cap_set
[1] = 1; /* # of capabilities integers */
225 cap_set
[2] = cpu_features
;
226 AcpiEvaluateObject(handle
, "_PDC", &arglist
, NULL
);
230 ksnprintf(sc
->cpu_sensdev
.xname
, sizeof(sc
->cpu_sensdev
.xname
), "%s",
231 device_get_nameunit(dev
));
232 sensordev_install(&sc
->cpu_sensdev
);
234 child
= BUS_ADD_CHILD(dev
, dev
, 0, "cpu_cst", -1);
237 acpi_set_handle(child
, handle
);
238 acpi_set_magic(child
, cpu_id
);
241 child
= BUS_ADD_CHILD(dev
, dev
, 0, "cpu_pst", -1);
244 acpi_set_handle(child
, handle
);
245 acpi_set_magic(child
, cpu_id
);
248 bus_generic_probe(dev
);
249 bus_generic_attach(dev
);
251 AcpiInstallNotifyHandler(handle
, ACPI_DEVICE_NOTIFY
, acpi_cpu_notify
, sc
);
257 * All resources are assigned directly to us by acpi,
258 * so 'child' is bypassed here.
260 static struct resource_list
*
261 acpi_cpu_get_rlist(device_t dev
, device_t child __unused
)
263 return BUS_GET_RESOURCE_LIST(device_get_parent(dev
), dev
);
266 static struct resource
*
267 acpi_cpu_alloc_resource(device_t dev
, device_t child __unused
,
268 int type
, int *rid
, u_long start
, u_long end
,
269 u_long count
, u_int flags
, int cpuid
)
271 return BUS_ALLOC_RESOURCE(device_get_parent(dev
), dev
, type
, rid
,
272 start
, end
, count
, flags
, cpuid
);
276 acpi_cpu_release_resource(device_t dev
, device_t child __unused
,
277 int type
, int rid
, struct resource
*r
)
279 return BUS_RELEASE_RESOURCE(device_get_parent(dev
), dev
, type
, rid
, r
);
283 * Find the nth present CPU and return its pc_cpuid as well as set the
284 * pc_acpi_id from the most reliable source.
287 acpi_cpu_get_id(uint32_t idx
, uint32_t *acpi_id
, uint32_t *cpu_id
)
289 struct mdglobaldata
*md
;
292 KASSERT(acpi_id
!= NULL
, ("Null acpi_id"));
293 KASSERT(cpu_id
!= NULL
, ("Null cpu_id"));
294 for (i
= 0; i
< ncpus
; i
++) {
295 if (CPUMASK_TESTBIT(smp_active_mask
, i
) == 0)
297 md
= (struct mdglobaldata
*)globaldata_find(i
);
298 KASSERT(md
!= NULL
, ("no pcpu data for %d", i
));
301 * If gd_acpi_id was not initialized (e.g., box w/o MADT)
302 * override it with the value from the ASL. Otherwise, if the
303 * two don't match, prefer the MADT-derived value. Finally,
304 * return the gd_cpuid to reference this processor.
306 if (md
->gd_acpi_id
== 0xffffffff) {
307 kprintf("cpu%d: acpi id was not set, set it to %u\n",
309 md
->gd_acpi_id
= *acpi_id
;
310 } else if (md
->gd_acpi_id
!= *acpi_id
) {
311 kprintf("cpu%d: acpi id mismatch, madt %u, "
312 "processor object %u\n",
313 i
, md
->gd_acpi_id
, *acpi_id
);
314 *acpi_id
= md
->gd_acpi_id
;
316 *cpu_id
= md
->mi
.gd_cpuid
;
324 acpi_cpu_notify(ACPI_HANDLE handler __unused
, UINT32 notify
, void *xsc
)
326 struct acpi_cpu_softc
*sc
= xsc
;
329 case ACPI_NOTIFY_CX_STATES
:
330 if (sc
->cpu_cst_notify
!= NULL
)
331 sc
->cpu_cst_notify(sc
->cpu_cst
);
333 case ACPI_NOTIFY_PX_STATES
:
334 if (sc
->cpu_pst_notify
!= NULL
)
335 sc
->cpu_pst_notify(sc
->cpu_pst
);
338 device_printf(sc
->cpu_dev
, "unknown notify: %#x\n", notify
);
343 static struct ksensordev
*
344 acpi_cpu_get_sensdev(device_t dev
)
346 struct acpi_cpu_softc
*sc
= device_get_softc(dev
);
348 return &sc
->cpu_sensdev
;