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 $
28 * $DragonFly: src/sys/dev/acpica5/acpi_cpu.c,v 1.21 2008/09/05 10:28:35 hasso Exp $
33 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/sysctl.h>
38 #include <machine/globaldata.h>
39 #include <machine/smp.h>
45 static int acpi_cpu_probe(device_t dev);
46 static int acpi_cpu_attach(device_t dev);
48 static int acpi_cpu_get_id(uint32_t, uint32_t *, uint32_t *);
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),
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),
77 static driver_t acpi_cpu_driver = {
80 sizeof(struct acpi_cpux_softc)
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);
88 acpi_cpu_probe(device_t dev)
96 if (acpi_disabled("cpu") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
99 handle = acpi_get_handle(dev);
102 * Get our Processor object.
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));
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);
120 acpi_id = obj->Processor.ProcId;
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.
128 if (acpi_cpu_get_id(device_get_unit(dev), &acpi_id, &cpu_id) != 0)
131 acpi_set_magic(dev, cpu_id);
132 device_set_desc(dev, "ACPI CPU");
138 acpi_cpu_attach(device_t dev)
140 struct acpi_cpux_softc *sc = device_get_softc(dev);
144 struct acpi_softc *acpi_sc;
146 handle = acpi_get_handle(dev);
147 cpu_id = acpi_get_magic(dev);
149 acpi_sc = acpi_device_get_parent_softc(dev);
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)
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);
170 child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1);
174 acpi_set_handle(child, handle);
175 acpi_set_magic(child, cpu_id);
177 bus_generic_attach(dev);
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.
187 acpi_cpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id)
189 struct mdglobaldata *md;
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)
197 md = (struct mdglobaldata *)globaldata_find(i);
198 KASSERT(md != NULL, ("no pcpu data for %d", i));
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.
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;