kernel - Add support for up to 63 cpus & 512G of ram for 64-bit builds.
[dragonfly.git] / sys / dev / acpica5 / acpi_cpu.c
CommitLineData
5ed44076 1/*-
5ebadb2c 2 * Copyright (c) 2003-2005 Nate Lawson (SDG)
5ed44076
MD
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 *
5ebadb2c
HT
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 $
5ed44076
MD
29 */
30
31#include "opt_acpi.h"
cc6e2b6e 32
5ed44076
MD
33#include <sys/param.h>
34#include <sys/bus.h>
35#include <sys/kernel.h>
cc6e2b6e 36#include <sys/sysctl.h>
5ed44076 37
5ed44076
MD
38#include <machine/globaldata.h>
39#include <machine/smp.h>
5ed44076
MD
40
41#include "acpi.h"
42#include "acpivar.h"
cc6e2b6e 43#include "acpi_cpu.h"
5ed44076 44
323b7a65
SZ
45#define ACPI_NOTIFY_CX_STATES 0x81 /* _CST changed. */
46
5ed44076
MD
47static int acpi_cpu_probe(device_t dev);
48static int acpi_cpu_attach(device_t dev);
caf65562
SZ
49static struct resource_list *
50 acpi_cpu_get_rlist(device_t, device_t);
51static struct resource *
52 acpi_cpu_alloc_resource(device_t, device_t,
53 int, int *, u_long, u_long, u_long, u_int);
54static int acpi_cpu_release_resource(device_t, device_t,
55 int, int, struct resource *);
5ebadb2c 56
cc6e2b6e 57static int acpi_cpu_get_id(uint32_t, uint32_t *, uint32_t *);
323b7a65 58static void acpi_cpu_notify(ACPI_HANDLE, UINT32, void *);
5ed44076
MD
59
60static device_method_t acpi_cpu_methods[] = {
61 /* Device interface */
cc6e2b6e
SZ
62 DEVMETHOD(device_probe, acpi_cpu_probe),
63 DEVMETHOD(device_attach, acpi_cpu_attach),
cc6e2b6e 64 DEVMETHOD(device_detach, bus_generic_detach),
caf65562 65 DEVMETHOD(device_shutdown, bus_generic_shutdown),
cc6e2b6e
SZ
66 DEVMETHOD(device_suspend, bus_generic_suspend),
67 DEVMETHOD(device_resume, bus_generic_resume),
5ebadb2c
HT
68
69 /* Bus interface */
cc6e2b6e
SZ
70 DEVMETHOD(bus_add_child, bus_generic_add_child),
71 DEVMETHOD(bus_print_child, bus_generic_print_child),
72 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar),
73 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar),
caf65562 74 DEVMETHOD(bus_get_resource_list, acpi_cpu_get_rlist),
cc6e2b6e
SZ
75 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
76 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
caf65562
SZ
77 DEVMETHOD(bus_alloc_resource, acpi_cpu_alloc_resource),
78 DEVMETHOD(bus_release_resource, acpi_cpu_release_resource),
cc6e2b6e
SZ
79 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
80 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
81 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
82 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
83 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
caf65562 84
cc6e2b6e 85 { 0, 0 }
5ed44076
MD
86};
87
88static driver_t acpi_cpu_driver = {
f9d8cd12 89 "cpu",
5ed44076 90 acpi_cpu_methods,
cc6e2b6e 91 sizeof(struct acpi_cpux_softc)
5ed44076
MD
92};
93
94static devclass_t acpi_cpu_devclass;
f9d8cd12
MD
95DRIVER_MODULE(cpu, acpi, acpi_cpu_driver, acpi_cpu_devclass, 0, 0);
96MODULE_DEPEND(cpu, acpi, 1, 1, 1);
5ed44076
MD
97
98static int
99acpi_cpu_probe(device_t dev)
100{
cc6e2b6e
SZ
101 int acpi_id, cpu_id;
102 ACPI_BUFFER buf;
103 ACPI_HANDLE handle;
104 ACPI_STATUS status;
105 ACPI_OBJECT *obj;
5ed44076 106
f9d8cd12 107 if (acpi_disabled("cpu") || acpi_get_type(dev) != ACPI_TYPE_PROCESSOR)
cc6e2b6e 108 return ENXIO;
5ed44076 109
f9d8cd12 110 handle = acpi_get_handle(dev);
5ed44076 111
cc6e2b6e
SZ
112 /*
113 * Get our Processor object.
114 */
f9d8cd12
MD
115 buf.Pointer = NULL;
116 buf.Length = ACPI_ALLOCATE_BUFFER;
117 status = AcpiEvaluateObject(handle, NULL, NULL, &buf);
5ed44076 118 if (ACPI_FAILURE(status)) {
f9d8cd12 119 device_printf(dev, "probe failed to get Processor obj - %s\n",
5ed44076 120 AcpiFormatException(status));
cc6e2b6e 121 return ENXIO;
5ed44076 122 }
cc6e2b6e 123
f9d8cd12
MD
124 obj = (ACPI_OBJECT *)buf.Pointer;
125 if (obj->Type != ACPI_TYPE_PROCESSOR) {
126 device_printf(dev, "Processor object has bad type %d\n", obj->Type);
127 AcpiOsFree(obj);
cc6e2b6e 128 return ENXIO;
5ed44076
MD
129 }
130
f9d8cd12
MD
131 acpi_id = obj->Processor.ProcId;
132 AcpiOsFree(obj);
5ed44076
MD
133
134 /*
cc6e2b6e
SZ
135 * Find the processor associated with our unit. We could use the
136 * ProcId as a key, however, some boxes do not have the same values
137 * in their Processor object as the ProcId values in the MADT.
5ed44076 138 */
cc6e2b6e
SZ
139 if (acpi_cpu_get_id(device_get_unit(dev), &acpi_id, &cpu_id) != 0)
140 return ENXIO;
5ed44076 141
f9d8cd12 142 acpi_set_magic(dev, cpu_id);
5ebadb2c 143 device_set_desc(dev, "ACPI CPU");
f9d8cd12 144
cc6e2b6e 145 return 0;
f9d8cd12
MD
146}
147
148static int
149acpi_cpu_attach(device_t dev)
150{
cc6e2b6e
SZ
151 struct acpi_cpux_softc *sc = device_get_softc(dev);
152 ACPI_HANDLE handle;
153 device_t child;
154 int cpu_id;
155 struct acpi_softc *acpi_sc;
f9d8cd12 156
cc6e2b6e 157 handle = acpi_get_handle(dev);
5ebadb2c 158 cpu_id = acpi_get_magic(dev);
f9d8cd12 159
cc6e2b6e
SZ
160 acpi_sc = acpi_device_get_parent_softc(dev);
161 if (cpu_id == 0) {
162 sysctl_ctx_init(&sc->glob_sysctl_ctx);
163 sc->glob_sysctl_tree = SYSCTL_ADD_NODE(&sc->glob_sysctl_ctx,
164 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
165 OID_AUTO, "cpu", CTLFLAG_RD, 0,
166 "node for CPU global settings");
167 if (sc->glob_sysctl_tree == NULL)
168 return ENOMEM;
f9d8cd12 169 }
5ebadb2c 170
cc6e2b6e
SZ
171 sysctl_ctx_init(&sc->pcpu_sysctl_ctx);
172 sc->pcpu_sysctl_tree = SYSCTL_ADD_NODE(&sc->pcpu_sysctl_ctx,
173 SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
174 OID_AUTO, device_get_nameunit(dev), CTLFLAG_RD, 0,
175 "node for per-CPU settings");
176 if (sc->pcpu_sysctl_tree == NULL) {
177 sysctl_ctx_free(&sc->glob_sysctl_ctx);
178 return ENOMEM;
5ebadb2c 179 }
5ed44076 180
cc6e2b6e
SZ
181 child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1);
182 if (child == NULL)
183 return ENXIO;
cc6e2b6e
SZ
184 acpi_set_handle(child, handle);
185 acpi_set_magic(child, cpu_id);
323b7a65 186 sc->cpux_cst = child;
5ebadb2c 187
c3a2c0df
SZ
188 child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1);
189 if (child == NULL)
190 return ENXIO;
191 acpi_set_handle(child, handle);
192 acpi_set_magic(child, cpu_id);
193
5ebadb2c
HT
194 bus_generic_attach(dev);
195
323b7a65
SZ
196 AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc);
197
cc6e2b6e 198 return 0;
5ed44076
MD
199}
200
caf65562
SZ
201/*
202 * All resources are assigned directly to us by acpi,
203 * so 'child' is bypassed here.
204 */
205static struct resource_list *
206acpi_cpu_get_rlist(device_t dev, device_t child __unused)
207{
208 return BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
209}
210
211static struct resource *
212acpi_cpu_alloc_resource(device_t dev, device_t child __unused,
213 int type, int *rid, u_long start, u_long end,
214 u_long count, u_int flags)
215{
216 return BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid,
217 start, end, count, flags);
218}
219
220static int
221acpi_cpu_release_resource(device_t dev, device_t child __unused,
222 int type, int rid, struct resource *r)
223{
224 return BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type, rid, r);
225}
226
5ed44076
MD
227/*
228 * Find the nth present CPU and return its pc_cpuid as well as set the
229 * pc_acpi_id from the most reliable source.
230 */
231static int
cc6e2b6e 232acpi_cpu_get_id(uint32_t idx, uint32_t *acpi_id, uint32_t *cpu_id)
5ed44076
MD
233{
234 struct mdglobaldata *md;
cc6e2b6e 235 uint32_t i;
5ed44076
MD
236
237 KASSERT(acpi_id != NULL, ("Null acpi_id"));
238 KASSERT(cpu_id != NULL, ("Null cpu_id"));
1fee1154 239 for (i = 0; i < ncpus; i++) {
da23a592 240 if ((smp_active_mask & CPUMASK(i)) == 0)
5ed44076
MD
241 continue;
242 md = (struct mdglobaldata *)globaldata_find(i);
243 KASSERT(md != NULL, ("no pcpu data for %d", i));
244 if (idx-- == 0) {
245 /*
246 * If pc_acpi_id was not initialized (e.g., a non-APIC UP box)
247 * override it with the value from the ASL. Otherwise, if the
248 * two don't match, prefer the MADT-derived value. Finally,
249 * return the pc_cpuid to reference this processor.
250 */
251 if (md->gd_acpi_id == 0xffffffff)
5ebadb2c 252 md->gd_acpi_id = *acpi_id;
5ed44076
MD
253 else if (md->gd_acpi_id != *acpi_id)
254 *acpi_id = md->gd_acpi_id;
255 *cpu_id = md->mi.gd_cpuid;
cc6e2b6e 256 return 0;
911afb96 257 }
5ebadb2c 258 }
cc6e2b6e 259 return ESRCH;
5ed44076 260}
323b7a65
SZ
261
262static void
263acpi_cpu_notify(ACPI_HANDLE handler __unused, UINT32 notify, void *xsc)
264{
265 struct acpi_cpux_softc *sc = xsc;
266
267 switch (notify) {
268 case ACPI_NOTIFY_CX_STATES:
269 if (sc->cpux_cst_notify != NULL)
270 sc->cpux_cst_notify(sc->cpux_cst);
271 break;
272 }
273}