acpi_cppc.c revision 1.2 1 1.2 thorpej /* $NetBSD: acpi_cppc.c,v 1.2 2021/01/29 15:49:55 thorpej Exp $ */
2 1.1 jmcneill
3 1.1 jmcneill /*-
4 1.1 jmcneill * Copyright (c) 2020 Jared McNeill <jmcneill (at) invisible.ca>
5 1.1 jmcneill * All rights reserved.
6 1.1 jmcneill *
7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without
8 1.1 jmcneill * modification, are permitted provided that the following conditions
9 1.1 jmcneill * are met:
10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright
11 1.1 jmcneill * notice, this list of conditions and the following disclaimer.
12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the
14 1.1 jmcneill * documentation and/or other materials provided with the distribution.
15 1.1 jmcneill *
16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE.
27 1.1 jmcneill */
28 1.1 jmcneill
29 1.1 jmcneill /*
30 1.1 jmcneill * ACPI Collaborative Processor Performance Control support.
31 1.1 jmcneill */
32 1.1 jmcneill
33 1.1 jmcneill #include <sys/cdefs.h>
34 1.2 thorpej __KERNEL_RCSID(0, "$NetBSD: acpi_cppc.c,v 1.2 2021/01/29 15:49:55 thorpej Exp $");
35 1.1 jmcneill
36 1.1 jmcneill #include <sys/param.h>
37 1.1 jmcneill #include <sys/bus.h>
38 1.1 jmcneill #include <sys/cpu.h>
39 1.1 jmcneill #include <sys/device.h>
40 1.1 jmcneill #include <sys/kmem.h>
41 1.1 jmcneill #include <sys/sysctl.h>
42 1.1 jmcneill
43 1.1 jmcneill #include <dev/acpi/acpireg.h>
44 1.1 jmcneill #include <dev/acpi/acpivar.h>
45 1.1 jmcneill #include <dev/acpi/acpi_pcc.h>
46 1.1 jmcneill
47 1.1 jmcneill #include <external/bsd/acpica/dist/include/amlresrc.h>
48 1.1 jmcneill
49 1.1 jmcneill /* _CPC package elements */
50 1.1 jmcneill typedef enum CPCPackageElement {
51 1.1 jmcneill CPCNumEntries,
52 1.1 jmcneill CPCRevision,
53 1.1 jmcneill CPCHighestPerformance,
54 1.1 jmcneill CPCNominalPerformance,
55 1.1 jmcneill CPCLowestNonlinearPerformance,
56 1.1 jmcneill CPCLowestPerformance,
57 1.1 jmcneill CPCGuaranteedPerformanceReg,
58 1.1 jmcneill CPCDesiredPerformanceReg,
59 1.1 jmcneill CPCMinimumPerformanceReg,
60 1.1 jmcneill CPCMaximumPerformanceReg,
61 1.1 jmcneill CPCPerformanceReductionToleranceReg,
62 1.1 jmcneill CPCTimeWindowReg,
63 1.1 jmcneill CPCCounterWraparoundTime,
64 1.1 jmcneill CPCReferencePerformanceCounterReg,
65 1.1 jmcneill CPCDeliveredPerformanceCounterReg,
66 1.1 jmcneill CPCPerformanceLimitedReg,
67 1.1 jmcneill CPCCPPCEnableReg,
68 1.1 jmcneill CPCAutonomousSelectionEnable,
69 1.1 jmcneill CPCAutonomousActivityWindowReg,
70 1.1 jmcneill CPCEnergyPerformancePreferenceReg,
71 1.1 jmcneill CPCReferencePerformance,
72 1.1 jmcneill CPCLowestFrequency,
73 1.1 jmcneill CPCNominalFrequency,
74 1.1 jmcneill } CPCPackageElement;
75 1.1 jmcneill
76 1.1 jmcneill /* PCC command numbers */
77 1.1 jmcneill #define CPPC_PCC_READ 0x00
78 1.1 jmcneill #define CPPC_PCC_WRITE 0x01
79 1.1 jmcneill
80 1.1 jmcneill struct cppc_softc {
81 1.1 jmcneill device_t sc_dev;
82 1.1 jmcneill struct cpu_info * sc_cpuinfo;
83 1.1 jmcneill ACPI_HANDLE sc_handle;
84 1.1 jmcneill ACPI_OBJECT * sc_cpc;
85 1.1 jmcneill u_int sc_ncpc;
86 1.1 jmcneill
87 1.1 jmcneill char * sc_available;
88 1.1 jmcneill int sc_node_target;
89 1.1 jmcneill int sc_node_current;
90 1.1 jmcneill ACPI_INTEGER sc_max_target;
91 1.1 jmcneill ACPI_INTEGER sc_min_target;
92 1.1 jmcneill };
93 1.1 jmcneill
94 1.1 jmcneill static int cppc_match(device_t, cfdata_t, void *);
95 1.1 jmcneill static void cppc_attach(device_t, device_t, void *);
96 1.1 jmcneill
97 1.1 jmcneill static ACPI_STATUS cppc_parse_cpc(struct cppc_softc *);
98 1.1 jmcneill static ACPI_STATUS cppc_cpufreq_init(struct cppc_softc *);
99 1.1 jmcneill static ACPI_STATUS cppc_read(struct cppc_softc *, CPCPackageElement,
100 1.1 jmcneill ACPI_INTEGER *);
101 1.1 jmcneill static ACPI_STATUS cppc_write(struct cppc_softc *, CPCPackageElement,
102 1.1 jmcneill ACPI_INTEGER);
103 1.1 jmcneill
104 1.1 jmcneill CFATTACH_DECL_NEW(acpicppc, sizeof(struct cppc_softc),
105 1.1 jmcneill cppc_match, cppc_attach, NULL, NULL);
106 1.1 jmcneill
107 1.2 thorpej static const struct device_compatible_entry compat_data[] = {
108 1.2 thorpej { .compat = "ACPI0007" }, /* ACPI Processor Device */
109 1.2 thorpej DEVICE_COMPAT_EOL
110 1.1 jmcneill };
111 1.1 jmcneill
112 1.1 jmcneill static int
113 1.1 jmcneill cppc_match(device_t parent, cfdata_t cf, void *aux)
114 1.1 jmcneill {
115 1.1 jmcneill struct acpi_attach_args * const aa = aux;
116 1.1 jmcneill ACPI_HANDLE handle;
117 1.1 jmcneill ACPI_STATUS rv;
118 1.1 jmcneill
119 1.2 thorpej if (acpi_compatible_match(aa, compat_data) == 0)
120 1.1 jmcneill return 0;
121 1.1 jmcneill
122 1.1 jmcneill rv = AcpiGetHandle(aa->aa_node->ad_handle, "_CPC", &handle);
123 1.1 jmcneill if (ACPI_FAILURE(rv)) {
124 1.1 jmcneill return 0;
125 1.1 jmcneill }
126 1.1 jmcneill
127 1.1 jmcneill if (acpi_match_cpu_handle(aa->aa_node->ad_handle) == NULL) {
128 1.1 jmcneill return 0;
129 1.1 jmcneill }
130 1.1 jmcneill
131 1.1 jmcneill /* When CPPC and P-states/T-states are both available, prefer CPPC */
132 1.2 thorpej return ACPI_MATCHSCORE_CID_MAX + 1;
133 1.1 jmcneill }
134 1.1 jmcneill
135 1.1 jmcneill static void
136 1.1 jmcneill cppc_attach(device_t parent, device_t self, void *aux)
137 1.1 jmcneill {
138 1.1 jmcneill struct cppc_softc * const sc = device_private(self);
139 1.1 jmcneill struct acpi_attach_args * const aa = aux;
140 1.1 jmcneill ACPI_HANDLE handle = aa->aa_node->ad_handle;
141 1.1 jmcneill struct cpu_info *ci;
142 1.1 jmcneill ACPI_STATUS rv;
143 1.1 jmcneill
144 1.1 jmcneill ci = acpi_match_cpu_handle(handle);
145 1.1 jmcneill KASSERT(ci != NULL);
146 1.1 jmcneill
147 1.1 jmcneill aprint_naive("\n");
148 1.1 jmcneill aprint_normal(": Processor Performance Control (%s)\n", cpu_name(ci));
149 1.1 jmcneill
150 1.1 jmcneill sc->sc_dev = self;
151 1.1 jmcneill sc->sc_cpuinfo = ci;
152 1.1 jmcneill sc->sc_handle = handle;
153 1.1 jmcneill
154 1.1 jmcneill rv = cppc_parse_cpc(sc);
155 1.1 jmcneill if (ACPI_FAILURE(rv)) {
156 1.1 jmcneill aprint_error_dev(self, "failed to parse CPC package: %s\n",
157 1.1 jmcneill AcpiFormatException(rv));
158 1.1 jmcneill return;
159 1.1 jmcneill }
160 1.1 jmcneill
161 1.1 jmcneill cppc_cpufreq_init(sc);
162 1.1 jmcneill }
163 1.1 jmcneill
164 1.1 jmcneill /*
165 1.1 jmcneill * cppc_parse_cpc --
166 1.1 jmcneill *
167 1.1 jmcneill * Read and verify the contents of the _CPC package.
168 1.1 jmcneill */
169 1.1 jmcneill static ACPI_STATUS
170 1.1 jmcneill cppc_parse_cpc(struct cppc_softc *sc)
171 1.1 jmcneill {
172 1.1 jmcneill ACPI_BUFFER buf;
173 1.1 jmcneill ACPI_STATUS rv;
174 1.1 jmcneill
175 1.1 jmcneill buf.Pointer = NULL;
176 1.1 jmcneill buf.Length = ACPI_ALLOCATE_BUFFER;
177 1.1 jmcneill rv = AcpiEvaluateObjectTyped(sc->sc_handle, "_CPC", NULL, &buf,
178 1.1 jmcneill ACPI_TYPE_PACKAGE);
179 1.1 jmcneill if (ACPI_FAILURE(rv)) {
180 1.1 jmcneill return rv;
181 1.1 jmcneill }
182 1.1 jmcneill
183 1.1 jmcneill sc->sc_cpc = (ACPI_OBJECT *)buf.Pointer;
184 1.1 jmcneill if (sc->sc_cpc->Package.Count == 0) {
185 1.1 jmcneill return AE_NOT_EXIST;
186 1.1 jmcneill }
187 1.1 jmcneill if (sc->sc_cpc->Package.Elements[CPCNumEntries].Type !=
188 1.1 jmcneill ACPI_TYPE_INTEGER) {
189 1.1 jmcneill return AE_TYPE;
190 1.1 jmcneill }
191 1.1 jmcneill sc->sc_ncpc =
192 1.1 jmcneill sc->sc_cpc->Package.Elements[CPCNumEntries].Integer.Value;
193 1.1 jmcneill
194 1.1 jmcneill return AE_OK;
195 1.1 jmcneill }
196 1.1 jmcneill
197 1.1 jmcneill /*
198 1.1 jmcneill * cppc_cpufreq_sysctl --
199 1.1 jmcneill *
200 1.1 jmcneill * sysctl helper function for machdep.cpu.cpuN.{target,current}
201 1.1 jmcneill * nodes.
202 1.1 jmcneill */
203 1.1 jmcneill static int
204 1.1 jmcneill cppc_cpufreq_sysctl(SYSCTLFN_ARGS)
205 1.1 jmcneill {
206 1.1 jmcneill struct cppc_softc * const sc = rnode->sysctl_data;
207 1.1 jmcneill struct sysctlnode node;
208 1.1 jmcneill u_int fq, oldfq = 0;
209 1.1 jmcneill ACPI_INTEGER val;
210 1.1 jmcneill ACPI_STATUS rv;
211 1.1 jmcneill int error;
212 1.1 jmcneill
213 1.1 jmcneill node = *rnode;
214 1.1 jmcneill node.sysctl_data = &fq;
215 1.1 jmcneill
216 1.1 jmcneill if (rnode->sysctl_num == sc->sc_node_target) {
217 1.1 jmcneill rv = cppc_read(sc, CPCDesiredPerformanceReg, &val);
218 1.1 jmcneill } else {
219 1.1 jmcneill /*
220 1.1 jmcneill * XXX We should measure the delivered performance and
221 1.1 jmcneill * report it here. For now, just report the desired
222 1.1 jmcneill * performance level.
223 1.1 jmcneill */
224 1.1 jmcneill rv = cppc_read(sc, CPCDesiredPerformanceReg, &val);
225 1.1 jmcneill }
226 1.1 jmcneill if (ACPI_FAILURE(rv)) {
227 1.1 jmcneill return EIO;
228 1.1 jmcneill }
229 1.1 jmcneill if (val > UINT32_MAX) {
230 1.1 jmcneill return ERANGE;
231 1.1 jmcneill }
232 1.1 jmcneill fq = (u_int)val;
233 1.1 jmcneill
234 1.1 jmcneill if (rnode->sysctl_num == sc->sc_node_target) {
235 1.1 jmcneill oldfq = fq;
236 1.1 jmcneill }
237 1.1 jmcneill
238 1.1 jmcneill error = sysctl_lookup(SYSCTLFN_CALL(&node));
239 1.1 jmcneill if (error != 0 || newp == NULL) {
240 1.1 jmcneill return error;
241 1.1 jmcneill }
242 1.1 jmcneill
243 1.1 jmcneill if (fq == oldfq || rnode->sysctl_num != sc->sc_node_target) {
244 1.1 jmcneill return 0;
245 1.1 jmcneill }
246 1.1 jmcneill
247 1.1 jmcneill if (fq < sc->sc_min_target || fq > sc->sc_max_target) {
248 1.1 jmcneill return EINVAL;
249 1.1 jmcneill }
250 1.1 jmcneill
251 1.1 jmcneill rv = cppc_write(sc, CPCDesiredPerformanceReg, fq);
252 1.1 jmcneill if (ACPI_FAILURE(rv)) {
253 1.1 jmcneill return EIO;
254 1.1 jmcneill }
255 1.1 jmcneill
256 1.1 jmcneill return 0;
257 1.1 jmcneill }
258 1.1 jmcneill
259 1.1 jmcneill /*
260 1.1 jmcneill * cppc_cpufreq_init --
261 1.1 jmcneill *
262 1.1 jmcneill * Create sysctl machdep.cpu.cpuN.* sysctl tree.
263 1.1 jmcneill */
264 1.1 jmcneill static ACPI_STATUS
265 1.1 jmcneill cppc_cpufreq_init(struct cppc_softc *sc)
266 1.1 jmcneill {
267 1.1 jmcneill static CPCPackageElement perf_regs[4] = {
268 1.1 jmcneill CPCHighestPerformance,
269 1.1 jmcneill CPCNominalPerformance,
270 1.1 jmcneill CPCLowestNonlinearPerformance,
271 1.1 jmcneill CPCLowestPerformance
272 1.1 jmcneill };
273 1.1 jmcneill ACPI_INTEGER perf[4], last;
274 1.1 jmcneill const struct sysctlnode *node, *cpunode;
275 1.1 jmcneill struct sysctllog *log = NULL;
276 1.1 jmcneill struct cpu_info *ci = sc->sc_cpuinfo;
277 1.1 jmcneill ACPI_STATUS rv;
278 1.1 jmcneill int error, i, n;
279 1.1 jmcneill
280 1.1 jmcneill /*
281 1.1 jmcneill * Read highest, nominal, lowest nonlinear, and lowest performance
282 1.1 jmcneill * levels and advertise this list of performance levels in the
283 1.1 jmcneill * machdep.cpufreq.cpuN.available sysctl.
284 1.1 jmcneill */
285 1.1 jmcneill sc->sc_available = kmem_zalloc(
286 1.1 jmcneill strlen("########## ") * __arraycount(perf_regs), KM_SLEEP);
287 1.1 jmcneill last = 0;
288 1.1 jmcneill for (i = 0, n = 0; i < __arraycount(perf_regs); i++) {
289 1.1 jmcneill rv = cppc_read(sc, perf_regs[i], &perf[i]);
290 1.1 jmcneill if (ACPI_FAILURE(rv)) {
291 1.1 jmcneill return rv;
292 1.1 jmcneill }
293 1.1 jmcneill if (perf[i] != last) {
294 1.1 jmcneill char buf[12];
295 1.1 jmcneill snprintf(buf, sizeof(buf), n ? " %u" : "%u",
296 1.1 jmcneill (u_int)perf[i]);
297 1.1 jmcneill strcat(sc->sc_available, buf);
298 1.1 jmcneill last = perf[i];
299 1.1 jmcneill n++;
300 1.1 jmcneill }
301 1.1 jmcneill }
302 1.1 jmcneill sc->sc_max_target = perf[0];
303 1.1 jmcneill sc->sc_min_target = perf[3];
304 1.1 jmcneill
305 1.1 jmcneill error = sysctl_createv(&log, 0, NULL, &node,
306 1.1 jmcneill CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
307 1.1 jmcneill NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
308 1.1 jmcneill if (error != 0) {
309 1.1 jmcneill goto sysctl_failed;
310 1.1 jmcneill }
311 1.1 jmcneill
312 1.1 jmcneill error = sysctl_createv(&log, 0, &node, &node,
313 1.1 jmcneill 0, CTLTYPE_NODE, "cpufreq", NULL,
314 1.1 jmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
315 1.1 jmcneill if (error != 0) {
316 1.1 jmcneill goto sysctl_failed;
317 1.1 jmcneill }
318 1.1 jmcneill
319 1.1 jmcneill error = sysctl_createv(&log, 0, &node, &cpunode,
320 1.1 jmcneill 0, CTLTYPE_NODE, cpu_name(ci), NULL,
321 1.1 jmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
322 1.1 jmcneill if (error != 0) {
323 1.1 jmcneill goto sysctl_failed;
324 1.1 jmcneill }
325 1.1 jmcneill
326 1.1 jmcneill error = sysctl_createv(&log, 0, &cpunode, &node,
327 1.1 jmcneill CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
328 1.1 jmcneill cppc_cpufreq_sysctl, 0, (void *)sc, 0,
329 1.1 jmcneill CTL_CREATE, CTL_EOL);
330 1.1 jmcneill if (error != 0) {
331 1.1 jmcneill goto sysctl_failed;
332 1.1 jmcneill }
333 1.1 jmcneill sc->sc_node_target = node->sysctl_num;
334 1.1 jmcneill
335 1.1 jmcneill error = sysctl_createv(&log, 0, &cpunode, &node,
336 1.1 jmcneill CTLFLAG_READONLY, CTLTYPE_INT, "current", NULL,
337 1.1 jmcneill cppc_cpufreq_sysctl, 0, (void *)sc, 0,
338 1.1 jmcneill CTL_CREATE, CTL_EOL);
339 1.1 jmcneill if (error != 0) {
340 1.1 jmcneill goto sysctl_failed;
341 1.1 jmcneill }
342 1.1 jmcneill sc->sc_node_current = node->sysctl_num;
343 1.1 jmcneill
344 1.1 jmcneill error = sysctl_createv(&log, 0, &cpunode, &node,
345 1.1 jmcneill CTLFLAG_READONLY, CTLTYPE_STRING, "available", NULL,
346 1.1 jmcneill NULL, 0, sc->sc_available, 0,
347 1.1 jmcneill CTL_CREATE, CTL_EOL);
348 1.1 jmcneill if (error != 0) {
349 1.1 jmcneill goto sysctl_failed;
350 1.1 jmcneill }
351 1.1 jmcneill
352 1.1 jmcneill return AE_OK;
353 1.1 jmcneill
354 1.1 jmcneill sysctl_failed:
355 1.1 jmcneill aprint_error_dev(sc->sc_dev, "couldn't create sysctl nodes: %d\n",
356 1.1 jmcneill error);
357 1.1 jmcneill sysctl_teardown(&log);
358 1.1 jmcneill
359 1.1 jmcneill return AE_ERROR;
360 1.1 jmcneill }
361 1.1 jmcneill
362 1.1 jmcneill /*
363 1.1 jmcneill * cppc_read --
364 1.1 jmcneill *
365 1.1 jmcneill * Read a value from the CPC package that contains either an integer
366 1.1 jmcneill * or indirect register reference.
367 1.1 jmcneill */
368 1.1 jmcneill static ACPI_STATUS
369 1.1 jmcneill cppc_read(struct cppc_softc *sc, CPCPackageElement index, ACPI_INTEGER *val)
370 1.1 jmcneill {
371 1.1 jmcneill ACPI_OBJECT *obj;
372 1.1 jmcneill ACPI_GENERIC_ADDRESS addr;
373 1.1 jmcneill ACPI_STATUS rv;
374 1.1 jmcneill
375 1.1 jmcneill if (index >= sc->sc_ncpc) {
376 1.1 jmcneill return AE_NOT_EXIST;
377 1.1 jmcneill }
378 1.1 jmcneill
379 1.1 jmcneill obj = &sc->sc_cpc->Package.Elements[index];
380 1.1 jmcneill switch (obj->Type) {
381 1.1 jmcneill case ACPI_TYPE_INTEGER:
382 1.1 jmcneill *val = obj->Integer.Value;
383 1.1 jmcneill return AE_OK;
384 1.1 jmcneill
385 1.1 jmcneill case ACPI_TYPE_BUFFER:
386 1.1 jmcneill if (obj->Buffer.Length <
387 1.1 jmcneill sizeof(AML_RESOURCE_GENERIC_REGISTER)) {
388 1.1 jmcneill return AE_TYPE;
389 1.1 jmcneill }
390 1.1 jmcneill memcpy(&addr, obj->Buffer.Pointer +
391 1.1 jmcneill sizeof(AML_RESOURCE_LARGE_HEADER), sizeof(addr));
392 1.1 jmcneill if (addr.SpaceId == ACPI_ADR_SPACE_PLATFORM_COMM) {
393 1.1 jmcneill rv = pcc_message(&addr, CPPC_PCC_READ, PCC_READ, val);
394 1.1 jmcneill } else {
395 1.1 jmcneill rv = AcpiRead(val, &addr);
396 1.1 jmcneill }
397 1.1 jmcneill return rv;
398 1.1 jmcneill
399 1.1 jmcneill default:
400 1.1 jmcneill return AE_SUPPORT;
401 1.1 jmcneill }
402 1.1 jmcneill }
403 1.1 jmcneill
404 1.1 jmcneill /*
405 1.1 jmcneill * cppc_write --
406 1.1 jmcneill *
407 1.1 jmcneill * Write a value based on the CPC package to the specified register.
408 1.1 jmcneill */
409 1.1 jmcneill static ACPI_STATUS
410 1.1 jmcneill cppc_write(struct cppc_softc *sc, CPCPackageElement index, ACPI_INTEGER val)
411 1.1 jmcneill {
412 1.1 jmcneill ACPI_OBJECT *obj;
413 1.1 jmcneill ACPI_GENERIC_ADDRESS addr;
414 1.1 jmcneill ACPI_STATUS rv;
415 1.1 jmcneill
416 1.1 jmcneill if (index >= sc->sc_ncpc) {
417 1.1 jmcneill return AE_NOT_EXIST;
418 1.1 jmcneill }
419 1.1 jmcneill
420 1.1 jmcneill obj = &sc->sc_cpc->Package.Elements[index];
421 1.1 jmcneill if (obj->Type != ACPI_TYPE_BUFFER ||
422 1.1 jmcneill obj->Buffer.Length < sizeof(AML_RESOURCE_GENERIC_REGISTER)) {
423 1.1 jmcneill return AE_TYPE;
424 1.1 jmcneill }
425 1.1 jmcneill
426 1.1 jmcneill memcpy(&addr, obj->Buffer.Pointer +
427 1.1 jmcneill sizeof(AML_RESOURCE_LARGE_HEADER), sizeof(addr));
428 1.1 jmcneill if (addr.SpaceId == ACPI_ADR_SPACE_PLATFORM_COMM) {
429 1.1 jmcneill rv = pcc_message(&addr, CPPC_PCC_WRITE, PCC_WRITE, &val);
430 1.1 jmcneill } else {
431 1.1 jmcneill rv = AcpiWrite(val, &addr);
432 1.1 jmcneill }
433 1.1 jmcneill
434 1.1 jmcneill return rv;
435 1.1 jmcneill }
436