acpi_cppc.c revision 1.1 1 1.1 jmcneill /* $NetBSD: acpi_cppc.c,v 1.1 2020/12/13 20:39:20 jmcneill 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.1 jmcneill __KERNEL_RCSID(0, "$NetBSD: acpi_cppc.c,v 1.1 2020/12/13 20:39:20 jmcneill 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.1 jmcneill static const char * const compatible[] = {
108 1.1 jmcneill "ACPI0007", /* ACPI Processor Device */
109 1.1 jmcneill NULL
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.1 jmcneill if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) {
120 1.1 jmcneill return 0;
121 1.1 jmcneill }
122 1.1 jmcneill
123 1.1 jmcneill if (acpi_match_hid(aa->aa_node->ad_devinfo, compatible) == 0) {
124 1.1 jmcneill return 0;
125 1.1 jmcneill }
126 1.1 jmcneill
127 1.1 jmcneill rv = AcpiGetHandle(aa->aa_node->ad_handle, "_CPC", &handle);
128 1.1 jmcneill if (ACPI_FAILURE(rv)) {
129 1.1 jmcneill return 0;
130 1.1 jmcneill }
131 1.1 jmcneill
132 1.1 jmcneill if (acpi_match_cpu_handle(aa->aa_node->ad_handle) == NULL) {
133 1.1 jmcneill return 0;
134 1.1 jmcneill }
135 1.1 jmcneill
136 1.1 jmcneill /* When CPPC and P-states/T-states are both available, prefer CPPC */
137 1.1 jmcneill return 20;
138 1.1 jmcneill }
139 1.1 jmcneill
140 1.1 jmcneill static void
141 1.1 jmcneill cppc_attach(device_t parent, device_t self, void *aux)
142 1.1 jmcneill {
143 1.1 jmcneill struct cppc_softc * const sc = device_private(self);
144 1.1 jmcneill struct acpi_attach_args * const aa = aux;
145 1.1 jmcneill ACPI_HANDLE handle = aa->aa_node->ad_handle;
146 1.1 jmcneill struct cpu_info *ci;
147 1.1 jmcneill ACPI_STATUS rv;
148 1.1 jmcneill
149 1.1 jmcneill ci = acpi_match_cpu_handle(handle);
150 1.1 jmcneill KASSERT(ci != NULL);
151 1.1 jmcneill
152 1.1 jmcneill aprint_naive("\n");
153 1.1 jmcneill aprint_normal(": Processor Performance Control (%s)\n", cpu_name(ci));
154 1.1 jmcneill
155 1.1 jmcneill sc->sc_dev = self;
156 1.1 jmcneill sc->sc_cpuinfo = ci;
157 1.1 jmcneill sc->sc_handle = handle;
158 1.1 jmcneill
159 1.1 jmcneill rv = cppc_parse_cpc(sc);
160 1.1 jmcneill if (ACPI_FAILURE(rv)) {
161 1.1 jmcneill aprint_error_dev(self, "failed to parse CPC package: %s\n",
162 1.1 jmcneill AcpiFormatException(rv));
163 1.1 jmcneill return;
164 1.1 jmcneill }
165 1.1 jmcneill
166 1.1 jmcneill cppc_cpufreq_init(sc);
167 1.1 jmcneill }
168 1.1 jmcneill
169 1.1 jmcneill /*
170 1.1 jmcneill * cppc_parse_cpc --
171 1.1 jmcneill *
172 1.1 jmcneill * Read and verify the contents of the _CPC package.
173 1.1 jmcneill */
174 1.1 jmcneill static ACPI_STATUS
175 1.1 jmcneill cppc_parse_cpc(struct cppc_softc *sc)
176 1.1 jmcneill {
177 1.1 jmcneill ACPI_BUFFER buf;
178 1.1 jmcneill ACPI_STATUS rv;
179 1.1 jmcneill
180 1.1 jmcneill buf.Pointer = NULL;
181 1.1 jmcneill buf.Length = ACPI_ALLOCATE_BUFFER;
182 1.1 jmcneill rv = AcpiEvaluateObjectTyped(sc->sc_handle, "_CPC", NULL, &buf,
183 1.1 jmcneill ACPI_TYPE_PACKAGE);
184 1.1 jmcneill if (ACPI_FAILURE(rv)) {
185 1.1 jmcneill return rv;
186 1.1 jmcneill }
187 1.1 jmcneill
188 1.1 jmcneill sc->sc_cpc = (ACPI_OBJECT *)buf.Pointer;
189 1.1 jmcneill if (sc->sc_cpc->Package.Count == 0) {
190 1.1 jmcneill return AE_NOT_EXIST;
191 1.1 jmcneill }
192 1.1 jmcneill if (sc->sc_cpc->Package.Elements[CPCNumEntries].Type !=
193 1.1 jmcneill ACPI_TYPE_INTEGER) {
194 1.1 jmcneill return AE_TYPE;
195 1.1 jmcneill }
196 1.1 jmcneill sc->sc_ncpc =
197 1.1 jmcneill sc->sc_cpc->Package.Elements[CPCNumEntries].Integer.Value;
198 1.1 jmcneill
199 1.1 jmcneill return AE_OK;
200 1.1 jmcneill }
201 1.1 jmcneill
202 1.1 jmcneill /*
203 1.1 jmcneill * cppc_cpufreq_sysctl --
204 1.1 jmcneill *
205 1.1 jmcneill * sysctl helper function for machdep.cpu.cpuN.{target,current}
206 1.1 jmcneill * nodes.
207 1.1 jmcneill */
208 1.1 jmcneill static int
209 1.1 jmcneill cppc_cpufreq_sysctl(SYSCTLFN_ARGS)
210 1.1 jmcneill {
211 1.1 jmcneill struct cppc_softc * const sc = rnode->sysctl_data;
212 1.1 jmcneill struct sysctlnode node;
213 1.1 jmcneill u_int fq, oldfq = 0;
214 1.1 jmcneill ACPI_INTEGER val;
215 1.1 jmcneill ACPI_STATUS rv;
216 1.1 jmcneill int error;
217 1.1 jmcneill
218 1.1 jmcneill node = *rnode;
219 1.1 jmcneill node.sysctl_data = &fq;
220 1.1 jmcneill
221 1.1 jmcneill if (rnode->sysctl_num == sc->sc_node_target) {
222 1.1 jmcneill rv = cppc_read(sc, CPCDesiredPerformanceReg, &val);
223 1.1 jmcneill } else {
224 1.1 jmcneill /*
225 1.1 jmcneill * XXX We should measure the delivered performance and
226 1.1 jmcneill * report it here. For now, just report the desired
227 1.1 jmcneill * performance level.
228 1.1 jmcneill */
229 1.1 jmcneill rv = cppc_read(sc, CPCDesiredPerformanceReg, &val);
230 1.1 jmcneill }
231 1.1 jmcneill if (ACPI_FAILURE(rv)) {
232 1.1 jmcneill return EIO;
233 1.1 jmcneill }
234 1.1 jmcneill if (val > UINT32_MAX) {
235 1.1 jmcneill return ERANGE;
236 1.1 jmcneill }
237 1.1 jmcneill fq = (u_int)val;
238 1.1 jmcneill
239 1.1 jmcneill if (rnode->sysctl_num == sc->sc_node_target) {
240 1.1 jmcneill oldfq = fq;
241 1.1 jmcneill }
242 1.1 jmcneill
243 1.1 jmcneill error = sysctl_lookup(SYSCTLFN_CALL(&node));
244 1.1 jmcneill if (error != 0 || newp == NULL) {
245 1.1 jmcneill return error;
246 1.1 jmcneill }
247 1.1 jmcneill
248 1.1 jmcneill if (fq == oldfq || rnode->sysctl_num != sc->sc_node_target) {
249 1.1 jmcneill return 0;
250 1.1 jmcneill }
251 1.1 jmcneill
252 1.1 jmcneill if (fq < sc->sc_min_target || fq > sc->sc_max_target) {
253 1.1 jmcneill return EINVAL;
254 1.1 jmcneill }
255 1.1 jmcneill
256 1.1 jmcneill rv = cppc_write(sc, CPCDesiredPerformanceReg, fq);
257 1.1 jmcneill if (ACPI_FAILURE(rv)) {
258 1.1 jmcneill return EIO;
259 1.1 jmcneill }
260 1.1 jmcneill
261 1.1 jmcneill return 0;
262 1.1 jmcneill }
263 1.1 jmcneill
264 1.1 jmcneill /*
265 1.1 jmcneill * cppc_cpufreq_init --
266 1.1 jmcneill *
267 1.1 jmcneill * Create sysctl machdep.cpu.cpuN.* sysctl tree.
268 1.1 jmcneill */
269 1.1 jmcneill static ACPI_STATUS
270 1.1 jmcneill cppc_cpufreq_init(struct cppc_softc *sc)
271 1.1 jmcneill {
272 1.1 jmcneill static CPCPackageElement perf_regs[4] = {
273 1.1 jmcneill CPCHighestPerformance,
274 1.1 jmcneill CPCNominalPerformance,
275 1.1 jmcneill CPCLowestNonlinearPerformance,
276 1.1 jmcneill CPCLowestPerformance
277 1.1 jmcneill };
278 1.1 jmcneill ACPI_INTEGER perf[4], last;
279 1.1 jmcneill const struct sysctlnode *node, *cpunode;
280 1.1 jmcneill struct sysctllog *log = NULL;
281 1.1 jmcneill struct cpu_info *ci = sc->sc_cpuinfo;
282 1.1 jmcneill ACPI_STATUS rv;
283 1.1 jmcneill int error, i, n;
284 1.1 jmcneill
285 1.1 jmcneill /*
286 1.1 jmcneill * Read highest, nominal, lowest nonlinear, and lowest performance
287 1.1 jmcneill * levels and advertise this list of performance levels in the
288 1.1 jmcneill * machdep.cpufreq.cpuN.available sysctl.
289 1.1 jmcneill */
290 1.1 jmcneill sc->sc_available = kmem_zalloc(
291 1.1 jmcneill strlen("########## ") * __arraycount(perf_regs), KM_SLEEP);
292 1.1 jmcneill last = 0;
293 1.1 jmcneill for (i = 0, n = 0; i < __arraycount(perf_regs); i++) {
294 1.1 jmcneill rv = cppc_read(sc, perf_regs[i], &perf[i]);
295 1.1 jmcneill if (ACPI_FAILURE(rv)) {
296 1.1 jmcneill return rv;
297 1.1 jmcneill }
298 1.1 jmcneill if (perf[i] != last) {
299 1.1 jmcneill char buf[12];
300 1.1 jmcneill snprintf(buf, sizeof(buf), n ? " %u" : "%u",
301 1.1 jmcneill (u_int)perf[i]);
302 1.1 jmcneill strcat(sc->sc_available, buf);
303 1.1 jmcneill last = perf[i];
304 1.1 jmcneill n++;
305 1.1 jmcneill }
306 1.1 jmcneill }
307 1.1 jmcneill sc->sc_max_target = perf[0];
308 1.1 jmcneill sc->sc_min_target = perf[3];
309 1.1 jmcneill
310 1.1 jmcneill error = sysctl_createv(&log, 0, NULL, &node,
311 1.1 jmcneill CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
312 1.1 jmcneill NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
313 1.1 jmcneill if (error != 0) {
314 1.1 jmcneill goto sysctl_failed;
315 1.1 jmcneill }
316 1.1 jmcneill
317 1.1 jmcneill error = sysctl_createv(&log, 0, &node, &node,
318 1.1 jmcneill 0, CTLTYPE_NODE, "cpufreq", NULL,
319 1.1 jmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
320 1.1 jmcneill if (error != 0) {
321 1.1 jmcneill goto sysctl_failed;
322 1.1 jmcneill }
323 1.1 jmcneill
324 1.1 jmcneill error = sysctl_createv(&log, 0, &node, &cpunode,
325 1.1 jmcneill 0, CTLTYPE_NODE, cpu_name(ci), NULL,
326 1.1 jmcneill NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
327 1.1 jmcneill if (error != 0) {
328 1.1 jmcneill goto sysctl_failed;
329 1.1 jmcneill }
330 1.1 jmcneill
331 1.1 jmcneill error = sysctl_createv(&log, 0, &cpunode, &node,
332 1.1 jmcneill CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL,
333 1.1 jmcneill cppc_cpufreq_sysctl, 0, (void *)sc, 0,
334 1.1 jmcneill CTL_CREATE, CTL_EOL);
335 1.1 jmcneill if (error != 0) {
336 1.1 jmcneill goto sysctl_failed;
337 1.1 jmcneill }
338 1.1 jmcneill sc->sc_node_target = node->sysctl_num;
339 1.1 jmcneill
340 1.1 jmcneill error = sysctl_createv(&log, 0, &cpunode, &node,
341 1.1 jmcneill CTLFLAG_READONLY, CTLTYPE_INT, "current", NULL,
342 1.1 jmcneill cppc_cpufreq_sysctl, 0, (void *)sc, 0,
343 1.1 jmcneill CTL_CREATE, CTL_EOL);
344 1.1 jmcneill if (error != 0) {
345 1.1 jmcneill goto sysctl_failed;
346 1.1 jmcneill }
347 1.1 jmcneill sc->sc_node_current = node->sysctl_num;
348 1.1 jmcneill
349 1.1 jmcneill error = sysctl_createv(&log, 0, &cpunode, &node,
350 1.1 jmcneill CTLFLAG_READONLY, CTLTYPE_STRING, "available", NULL,
351 1.1 jmcneill NULL, 0, sc->sc_available, 0,
352 1.1 jmcneill CTL_CREATE, CTL_EOL);
353 1.1 jmcneill if (error != 0) {
354 1.1 jmcneill goto sysctl_failed;
355 1.1 jmcneill }
356 1.1 jmcneill
357 1.1 jmcneill return AE_OK;
358 1.1 jmcneill
359 1.1 jmcneill sysctl_failed:
360 1.1 jmcneill aprint_error_dev(sc->sc_dev, "couldn't create sysctl nodes: %d\n",
361 1.1 jmcneill error);
362 1.1 jmcneill sysctl_teardown(&log);
363 1.1 jmcneill
364 1.1 jmcneill return AE_ERROR;
365 1.1 jmcneill }
366 1.1 jmcneill
367 1.1 jmcneill /*
368 1.1 jmcneill * cppc_read --
369 1.1 jmcneill *
370 1.1 jmcneill * Read a value from the CPC package that contains either an integer
371 1.1 jmcneill * or indirect register reference.
372 1.1 jmcneill */
373 1.1 jmcneill static ACPI_STATUS
374 1.1 jmcneill cppc_read(struct cppc_softc *sc, CPCPackageElement index, ACPI_INTEGER *val)
375 1.1 jmcneill {
376 1.1 jmcneill ACPI_OBJECT *obj;
377 1.1 jmcneill ACPI_GENERIC_ADDRESS addr;
378 1.1 jmcneill ACPI_STATUS rv;
379 1.1 jmcneill
380 1.1 jmcneill if (index >= sc->sc_ncpc) {
381 1.1 jmcneill return AE_NOT_EXIST;
382 1.1 jmcneill }
383 1.1 jmcneill
384 1.1 jmcneill obj = &sc->sc_cpc->Package.Elements[index];
385 1.1 jmcneill switch (obj->Type) {
386 1.1 jmcneill case ACPI_TYPE_INTEGER:
387 1.1 jmcneill *val = obj->Integer.Value;
388 1.1 jmcneill return AE_OK;
389 1.1 jmcneill
390 1.1 jmcneill case ACPI_TYPE_BUFFER:
391 1.1 jmcneill if (obj->Buffer.Length <
392 1.1 jmcneill sizeof(AML_RESOURCE_GENERIC_REGISTER)) {
393 1.1 jmcneill return AE_TYPE;
394 1.1 jmcneill }
395 1.1 jmcneill memcpy(&addr, obj->Buffer.Pointer +
396 1.1 jmcneill sizeof(AML_RESOURCE_LARGE_HEADER), sizeof(addr));
397 1.1 jmcneill if (addr.SpaceId == ACPI_ADR_SPACE_PLATFORM_COMM) {
398 1.1 jmcneill rv = pcc_message(&addr, CPPC_PCC_READ, PCC_READ, val);
399 1.1 jmcneill } else {
400 1.1 jmcneill rv = AcpiRead(val, &addr);
401 1.1 jmcneill }
402 1.1 jmcneill return rv;
403 1.1 jmcneill
404 1.1 jmcneill default:
405 1.1 jmcneill return AE_SUPPORT;
406 1.1 jmcneill }
407 1.1 jmcneill }
408 1.1 jmcneill
409 1.1 jmcneill /*
410 1.1 jmcneill * cppc_write --
411 1.1 jmcneill *
412 1.1 jmcneill * Write a value based on the CPC package to the specified register.
413 1.1 jmcneill */
414 1.1 jmcneill static ACPI_STATUS
415 1.1 jmcneill cppc_write(struct cppc_softc *sc, CPCPackageElement index, ACPI_INTEGER val)
416 1.1 jmcneill {
417 1.1 jmcneill ACPI_OBJECT *obj;
418 1.1 jmcneill ACPI_GENERIC_ADDRESS addr;
419 1.1 jmcneill ACPI_STATUS rv;
420 1.1 jmcneill
421 1.1 jmcneill if (index >= sc->sc_ncpc) {
422 1.1 jmcneill return AE_NOT_EXIST;
423 1.1 jmcneill }
424 1.1 jmcneill
425 1.1 jmcneill obj = &sc->sc_cpc->Package.Elements[index];
426 1.1 jmcneill if (obj->Type != ACPI_TYPE_BUFFER ||
427 1.1 jmcneill obj->Buffer.Length < sizeof(AML_RESOURCE_GENERIC_REGISTER)) {
428 1.1 jmcneill return AE_TYPE;
429 1.1 jmcneill }
430 1.1 jmcneill
431 1.1 jmcneill memcpy(&addr, obj->Buffer.Pointer +
432 1.1 jmcneill sizeof(AML_RESOURCE_LARGE_HEADER), sizeof(addr));
433 1.1 jmcneill if (addr.SpaceId == ACPI_ADR_SPACE_PLATFORM_COMM) {
434 1.1 jmcneill rv = pcc_message(&addr, CPPC_PCC_WRITE, PCC_WRITE, &val);
435 1.1 jmcneill } else {
436 1.1 jmcneill rv = AcpiWrite(val, &addr);
437 1.1 jmcneill }
438 1.1 jmcneill
439 1.1 jmcneill return rv;
440 1.1 jmcneill }
441