acpi/pstate: Since AMD 11h, 8 P-states are supported.
[dragonfly.git] / sys / platform / pc64 / acpica / acpi_pstate_machdep.c
CommitLineData
e774ca6d
MD
1/*
2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
3 *
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/param.h>
5e06f1b9 36#include <sys/kernel.h>
e774ca6d
MD
37#include <sys/systm.h>
38#include <sys/globaldata.h>
39
40#include <machine/md_var.h>
41#include <machine/cpufunc.h>
42#include <machine/cpufreq.h>
86b7a03a 43#include <machine/cputypes.h>
e774ca6d
MD
44#include <machine/specialreg.h>
45
46#include "acpi.h"
47#include "acpi_cpu_pstate.h"
48
49#define AMD_APMI_HWPSTATE 0x80
50
51#define AMD_MSR_PSTATE_CSR_MASK 0x7ULL
52#define AMD1X_MSR_PSTATE_CTL 0xc0010062
53#define AMD1X_MSR_PSTATE_ST 0xc0010063
54
55#define AMD_MSR_PSTATE_EN 0x8000000000000000ULL
56
57#define AMD10_MSR_PSTATE_START 0xc0010064
58#define AMD10_MSR_PSTATE_COUNT 5
465a6ec2 59#define AMD11_MSR_PSTATE_COUNT 8 /* starting from 11h */
e774ca6d
MD
60
61#define AMD0F_PST_CTL_FID(cval) (((cval) >> 0) & 0x3f)
62#define AMD0F_PST_CTL_VID(cval) (((cval) >> 6) & 0x1f)
63#define AMD0F_PST_CTL_VST(cval) (((cval) >> 11) & 0x7f)
64#define AMD0F_PST_CTL_MVS(cval) (((cval) >> 18) & 0x3)
65#define AMD0F_PST_CTL_PLLTIME(cval) (((cval) >> 20) & 0x7f)
66#define AMD0F_PST_CTL_RVO(cval) (((cval) >> 28) & 0x3)
67#define AMD0F_PST_CTL_IRT(cval) (((cval) >> 30) & 0x3)
68
69#define AMD0F_PST_ST_FID(sval) (((sval) >> 0) & 0x3f)
70#define AMD0F_PST_ST_VID(sval) (((sval) >> 6) & 0x3f)
71
72#define INTEL_MSR_MISC_ENABLE 0x1a0
73#define INTEL_MSR_MISC_EST_EN 0x10000ULL
74
75#define INTEL_MSR_PERF_STATUS 0x198
76#define INTEL_MSR_PERF_CTL 0x199
77#define INTEL_MSR_PERF_MASK 0xffffULL
78
79static const struct acpi_pst_md *
80 acpi_pst_amd_probe(void);
81static int acpi_pst_amd_check_csr(const struct acpi_pst_res *,
82 const struct acpi_pst_res *);
83static int acpi_pst_amd1x_check_pstates(const struct acpi_pstate *, int,
84 uint32_t, uint32_t);
85static int acpi_pst_amd10_check_pstates(const struct acpi_pstate *, int);
86static int acpi_pst_amd0f_check_pstates(const struct acpi_pstate *, int);
87static int acpi_pst_amd_init(const struct acpi_pst_res *,
88 const struct acpi_pst_res *);
89static int acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *,
90 const struct acpi_pst_res *, const struct acpi_pstate *);
91static int acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *,
92 const struct acpi_pst_res *, const struct acpi_pstate *);
93static const struct acpi_pstate *
94 acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *,
95 const struct acpi_pstate *, int);
96static const struct acpi_pstate *
97 acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *,
98 const struct acpi_pstate *, int);
99
100static const struct acpi_pst_md *
101 acpi_pst_intel_probe(void);
102static int acpi_pst_intel_check_csr(const struct acpi_pst_res *,
103 const struct acpi_pst_res *);
104static int acpi_pst_intel_check_pstates(const struct acpi_pstate *, int);
105static int acpi_pst_intel_init(const struct acpi_pst_res *,
106 const struct acpi_pst_res *);
107static int acpi_pst_intel_set_pstate(const struct acpi_pst_res *,
108 const struct acpi_pst_res *, const struct acpi_pstate *);
109static const struct acpi_pstate *
110 acpi_pst_intel_get_pstate(const struct acpi_pst_res *,
111 const struct acpi_pstate *, int);
112
113static int acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS *);
114static int acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS *);
115static uint32_t acpi_pst_md_res_read(const struct acpi_pst_res *);
116static void acpi_pst_md_res_write(const struct acpi_pst_res *, uint32_t);
117
118static const struct acpi_pst_md acpi_pst_amd10 = {
119 .pmd_check_csr = acpi_pst_amd_check_csr,
120 .pmd_check_pstates = acpi_pst_amd10_check_pstates,
121 .pmd_init = acpi_pst_amd_init,
122 .pmd_set_pstate = acpi_pst_amd1x_set_pstate,
123 .pmd_get_pstate = acpi_pst_amd1x_get_pstate
124};
125
126static const struct acpi_pst_md acpi_pst_amd0f = {
127 .pmd_check_csr = acpi_pst_amd_check_csr,
128 .pmd_check_pstates = acpi_pst_amd0f_check_pstates,
129 .pmd_init = acpi_pst_amd_init,
130 .pmd_set_pstate = acpi_pst_amd0f_set_pstate,
131 .pmd_get_pstate = acpi_pst_amd0f_get_pstate
132};
133
134static const struct acpi_pst_md acpi_pst_intel = {
135 .pmd_check_csr = acpi_pst_intel_check_csr,
136 .pmd_check_pstates = acpi_pst_intel_check_pstates,
137 .pmd_init = acpi_pst_intel_init,
138 .pmd_set_pstate = acpi_pst_intel_set_pstate,
139 .pmd_get_pstate = acpi_pst_intel_get_pstate
140};
141
5e06f1b9
SZ
142static int acpi_pst_stringent_check = 1;
143TUNABLE_INT("hw.acpi.cpu.pstate.strigent_check", &acpi_pst_stringent_check);
144
465a6ec2
SZ
145static int acpi_pst_amd1x_msr_pstate_count = AMD10_MSR_PSTATE_COUNT;
146
e774ca6d
MD
147const struct acpi_pst_md *
148acpi_pst_md_probe(void)
149{
86b7a03a 150 if (cpu_vendor_id == CPU_VENDOR_AMD)
e774ca6d 151 return acpi_pst_amd_probe();
86b7a03a 152 else if (cpu_vendor_id == CPU_VENDOR_INTEL)
e774ca6d
MD
153 return acpi_pst_intel_probe();
154 return NULL;
155}
156
157static const struct acpi_pst_md *
158acpi_pst_amd_probe(void)
159{
e876e4b5 160 uint32_t regs[4];
e774ca6d 161
e876e4b5
SZ
162 /* Only Family >= 0fh has P-State support */
163 if (CPUID_TO_FAMILY(cpu_id) < 0xf)
e774ca6d
MD
164 return NULL;
165
166 /* Check whether APMI exists */
e876e4b5 167 if (cpu_exthigh < 0x80000007)
e774ca6d
MD
168 return NULL;
169
170 /* Fetch APMI */
171 do_cpuid(0x80000007, regs);
172
e876e4b5 173 if (CPUID_TO_FAMILY(cpu_id) == 0xf) { /* Family 0fh */
e774ca6d
MD
174 if ((regs[3] & 0x06) == 0x06)
175 return &acpi_pst_amd0f;
e876e4b5 176 } else if (CPUID_TO_FAMILY(cpu_id) >= 0x10) { /* Family >= 10h */
465a6ec2
SZ
177 if (CPUID_TO_FAMILY(cpu_id) >= 0x11) {
178 acpi_pst_amd1x_msr_pstate_count =
179 AMD11_MSR_PSTATE_COUNT;
180 }
e774ca6d
MD
181 if (regs[3] & 0x80)
182 return &acpi_pst_amd10;
e774ca6d
MD
183 }
184 return NULL;
185}
186
187static int
188acpi_pst_amd_check_csr(const struct acpi_pst_res *ctrl,
189 const struct acpi_pst_res *status)
190{
191 if (ctrl->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
192 kprintf("cpu%d: Invalid P-State control register\n", mycpuid);
193 return EINVAL;
194 }
195 if (status->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
196 kprintf("cpu%d: Invalid P-State status register\n", mycpuid);
197 return EINVAL;
198 }
199 return 0;
200}
201
202static int
203acpi_pst_amd1x_check_pstates(const struct acpi_pstate *pstates, int npstates,
204 uint32_t msr_start, uint32_t msr_end)
205{
206 int i;
207
208 /*
209 * Make sure that related MSR P-State registers are enabled.
210 *
211 * NOTE:
212 * We don't check status register value here;
213 * it will not be used.
214 */
215 for (i = 0; i < npstates; ++i) {
216 uint64_t pstate;
217 uint32_t msr;
218
219 msr = msr_start +
220 (pstates[i].st_cval & AMD_MSR_PSTATE_CSR_MASK);
221 if (msr >= msr_end) {
222 kprintf("cpu%d: MSR P-State register %#08x "
223 "does not exist\n", mycpuid, msr);
224 return EINVAL;
225 }
226
227 pstate = rdmsr(msr);
228 if ((pstate & AMD_MSR_PSTATE_EN) == 0) {
229 kprintf("cpu%d: MSR P-State register %#08x "
230 "is not enabled\n", mycpuid, msr);
231 return EINVAL;
232 }
233 }
234 return 0;
235}
236
237static int
238acpi_pst_amd10_check_pstates(const struct acpi_pstate *pstates, int npstates)
239{
465a6ec2
SZ
240 if (npstates > acpi_pst_amd1x_msr_pstate_count) {
241 kprintf("cpu%d: only %d P-states are allowed\n", mycpuid,
242 acpi_pst_amd1x_msr_pstate_count);
e774ca6d
MD
243 return EINVAL;
244 }
245
246 return acpi_pst_amd1x_check_pstates(pstates, npstates,
247 AMD10_MSR_PSTATE_START,
248 AMD10_MSR_PSTATE_START + AMD10_MSR_PSTATE_COUNT);
249}
250
251static int
252acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *ctrl __unused,
253 const struct acpi_pst_res *status __unused,
254 const struct acpi_pstate *pstate)
255{
256 uint64_t cval;
257
258 cval = pstate->st_cval & AMD_MSR_PSTATE_CSR_MASK;
259 wrmsr(AMD1X_MSR_PSTATE_CTL, cval);
260
261 /*
262 * Don't check AMD1X_MSR_PSTATE_ST here, since it is
263 * affected by various P-State limits.
264 *
265 * For details:
266 * AMD Family 10h Processor BKDG Rev 3.20 (#31116)
267 * 2.4.2.4 P-state Transition Behavior
268 */
269
270 return 0;
271}
272
273static const struct acpi_pstate *
274acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *status __unused,
275 const struct acpi_pstate *pstates, int npstates)
276{
277 uint64_t sval;
278 int i;
279
280 sval = rdmsr(AMD1X_MSR_PSTATE_ST) & AMD_MSR_PSTATE_CSR_MASK;
281 for (i = 0; i < npstates; ++i) {
282 if ((pstates[i].st_sval & AMD_MSR_PSTATE_CSR_MASK) == sval)
283 return &pstates[i];
284 }
285 return NULL;
286}
287
288static int
289acpi_pst_amd0f_check_pstates(const struct acpi_pstate *pstates, int npstates)
290{
291 struct amd0f_fidvid fv_max, fv_min;
292 int i;
293
294 amd0f_fidvid_limit(&fv_min, &fv_max);
295
ed468a9a
SZ
296 if (fv_min.fid == fv_max.fid && fv_min.vid == fv_max.vid) {
297 kprintf("cpu%d: only one P-State is supported\n", mycpuid);
5e06f1b9
SZ
298 if (acpi_pst_stringent_check)
299 return EOPNOTSUPP;
ed468a9a
SZ
300 }
301
e774ca6d
MD
302 for (i = 0; i < npstates; ++i) {
303 const struct acpi_pstate *p = &pstates[i];
304 uint32_t fid, vid, mvs, rvo;
305 int mvs_mv, rvo_mv;
306
307 fid = AMD0F_PST_CTL_FID(p->st_cval);
308 vid = AMD0F_PST_CTL_VID(p->st_cval);
309
ed468a9a
SZ
310 if (i == 0) {
311 if (vid != fv_max.vid) {
312 kprintf("cpu%d: max VID mismatch "
313 "real %u, lim %d\n", mycpuid,
314 vid, fv_max.vid);
315 }
316 if (fid != fv_max.fid) {
317 kprintf("cpu%d: max FID mismatch "
318 "real %u, lim %d\n", mycpuid,
319 fid, fv_max.fid);
320 }
321 } else if (i == npstates - 1) {
322 if (vid != fv_min.vid) {
323 kprintf("cpu%d: min VID mismatch "
324 "real %u, lim %d\n", mycpuid,
325 vid, fv_min.vid);
326 }
327 if (fid != fv_min.fid) {
328 kprintf("cpu%d: min FID mismatch "
329 "real %u, lim %d\n", mycpuid,
330 fid, fv_min.fid);
331 }
332 } else {
333 if (fid >= fv_max.fid || fid < (fv_min.fid + 0x8)) {
334 kprintf("cpu%d: Invalid FID %#x, "
335 "out [%#x, %#x]\n", mycpuid, fid,
336 fv_min.fid + 0x8, fv_max.fid);
5e06f1b9
SZ
337 if (acpi_pst_stringent_check)
338 return EINVAL;
ed468a9a
SZ
339 }
340 if (vid < fv_max.vid || vid > fv_min.vid) {
341 kprintf("cpu%d: Invalid VID %#x, "
342 "in [%#x, %#x]\n", mycpuid, vid,
343 fv_max.vid, fv_min.vid);
5e06f1b9
SZ
344 if (acpi_pst_stringent_check)
345 return EINVAL;
ed468a9a 346 }
e774ca6d
MD
347 }
348
349 mvs = AMD0F_PST_CTL_MVS(p->st_cval);
350 rvo = AMD0F_PST_CTL_RVO(p->st_cval);
351
352 /* Only 0 is allowed, i.e. 25mV stepping */
353 if (mvs != 0) {
354 kprintf("cpu%d: Invalid MVS %#x\n", mycpuid, mvs);
355 return EINVAL;
356 }
357
358 /* -> mV */
359 mvs_mv = 25 * (1 << mvs);
360 rvo_mv = 25 * rvo;
361 if (rvo_mv % mvs_mv != 0) {
362 kprintf("cpu%d: Invalid MVS/RVO (%#x/%#x)\n",
363 mycpuid, mvs, rvo);
364 return EINVAL;
365 }
366 }
367 return 0;
368}
369
370static int
371acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *ctrl __unused,
372 const struct acpi_pst_res *status __unused,
373 const struct acpi_pstate *pstate)
374{
375 struct amd0f_fidvid fv;
376 struct amd0f_xsit xsit;
377
378 fv.fid = AMD0F_PST_CTL_FID(pstate->st_cval);
379 fv.vid = AMD0F_PST_CTL_VID(pstate->st_cval);
380
381 xsit.rvo = AMD0F_PST_CTL_RVO(pstate->st_cval);
382 xsit.mvs = AMD0F_PST_CTL_MVS(pstate->st_cval);
383 xsit.vst = AMD0F_PST_CTL_VST(pstate->st_cval);
384 xsit.pll_time = AMD0F_PST_CTL_PLLTIME(pstate->st_cval);
385 xsit.irt = AMD0F_PST_CTL_IRT(pstate->st_cval);
386
387 return amd0f_set_fidvid(&fv, &xsit);
388}
389
390static const struct acpi_pstate *
391acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *status __unused,
392 const struct acpi_pstate *pstates, int npstates)
393{
394 struct amd0f_fidvid fv;
395 int error, i;
396
397 error = amd0f_get_fidvid(&fv);
398 if (error)
399 return NULL;
400
401 for (i = 0; i < npstates; ++i) {
402 const struct acpi_pstate *p = &pstates[i];
403
404 if (fv.fid == AMD0F_PST_ST_FID(p->st_sval) &&
405 fv.vid == AMD0F_PST_ST_VID(p->st_sval))
406 return p;
407 }
408 return NULL;
409}
410
411static int
412acpi_pst_amd_init(const struct acpi_pst_res *ctrl __unused,
413 const struct acpi_pst_res *status __unused)
414{
415 return 0;
416}
417
418static const struct acpi_pst_md *
419acpi_pst_intel_probe(void)
420{
e774ca6d
MD
421 if ((cpu_feature2 & CPUID2_EST) == 0)
422 return NULL;
423
7d338ab4
SZ
424 if (CPUID_TO_FAMILY(cpu_id) >= 0xf || CPUID_TO_FAMILY(cpu_id) == 0x6)
425 return &acpi_pst_intel;
426
427 return NULL;
e774ca6d
MD
428}
429
430static int
431acpi_pst_intel_check_csr(const struct acpi_pst_res *ctrl,
432 const struct acpi_pst_res *status)
433{
434 int error;
435
436 if (ctrl->pr_gas.SpaceId != status->pr_gas.SpaceId) {
437 kprintf("cpu%d: P-State control(%d)/status(%d) registers have "
438 "different SpaceId", mycpuid,
439 ctrl->pr_gas.SpaceId, status->pr_gas.SpaceId);
440 return EINVAL;
441 }
442
443 switch (ctrl->pr_gas.SpaceId) {
444 case ACPI_ADR_SPACE_FIXED_HARDWARE:
445 if (ctrl->pr_res != NULL || status->pr_res != NULL) {
446 /* XXX should panic() */
447 kprintf("cpu%d: Allocated resource for fixed hardware "
448 "registers\n", mycpuid);
449 return EINVAL;
450 }
451 break;
452
453 case ACPI_ADR_SPACE_SYSTEM_IO:
454 if (ctrl->pr_res == NULL) {
455 kprintf("cpu%d: ioport allocation failed for control "
456 "register\n", mycpuid);
457 return ENXIO;
458 }
459 error = acpi_pst_md_gas_verify(&ctrl->pr_gas);
460 if (error) {
461 kprintf("cpu%d: Invalid control register GAS\n",
462 mycpuid);
463 return error;
464 }
465
466 if (status->pr_res == NULL) {
467 kprintf("cpu%d: ioport allocation failed for status "
468 "register\n", mycpuid);
469 return ENXIO;
470 }
471 error = acpi_pst_md_gas_verify(&status->pr_gas);
472 if (error) {
473 kprintf("cpu%d: Invalid status register GAS\n",
474 mycpuid);
475 return error;
476 }
477 break;
478
479 default:
480 kprintf("cpu%d: Invalid P-State control/status register "
481 "SpaceId %d\n", mycpuid, ctrl->pr_gas.SpaceId);
482 return EOPNOTSUPP;
483 }
484 return 0;
485}
486
487static int
488acpi_pst_intel_check_pstates(const struct acpi_pstate *pstates __unused,
489 int npstates __unused)
490{
491 return 0;
492}
493
494static int
495acpi_pst_intel_init(const struct acpi_pst_res *ctrl __unused,
496 const struct acpi_pst_res *status __unused)
497{
e774ca6d
MD
498 uint64_t misc_enable;
499
7d338ab4
SZ
500 if (CPUID_TO_FAMILY(cpu_id) == 0xf ||
501 (CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) < 0xd)) {
e774ca6d
MD
502 /* EST enable bit is reserved in INTEL_MSR_MISC_ENABLE */
503 return 0;
504 }
505
506 misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
507 if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
508 misc_enable |= INTEL_MSR_MISC_EST_EN;
509 wrmsr(INTEL_MSR_MISC_ENABLE, misc_enable);
510
511 misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
512 if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
513 kprintf("cpu%d: Can't enable EST\n", mycpuid);
514 return EIO;
515 }
516 }
517 return 0;
518}
519
520static int
521acpi_pst_intel_set_pstate(const struct acpi_pst_res *ctrl,
522 const struct acpi_pst_res *status __unused,
523 const struct acpi_pstate *pstate)
524{
525 if (ctrl->pr_res != NULL) {
526 acpi_pst_md_res_write(ctrl, pstate->st_cval);
527 } else {
528 uint64_t ctl;
529
530 ctl = rdmsr(INTEL_MSR_PERF_CTL);
531 ctl &= ~INTEL_MSR_PERF_MASK;
532 ctl |= (pstate->st_cval & INTEL_MSR_PERF_MASK);
533 wrmsr(INTEL_MSR_PERF_CTL, ctl);
534 }
535 return 0;
536}
537
538static const struct acpi_pstate *
539acpi_pst_intel_get_pstate(const struct acpi_pst_res *status,
540 const struct acpi_pstate *pstates, int npstates)
541{
542 int i;
543
544 if (status->pr_res != NULL) {
545 uint32_t st;
546
547 st = acpi_pst_md_res_read(status);
548 for (i = 0; i < npstates; ++i) {
549 if (pstates[i].st_sval == st)
550 return &pstates[i];
551 }
552 } else {
553 uint64_t sval;
554
555 sval = rdmsr(INTEL_MSR_PERF_STATUS) & INTEL_MSR_PERF_MASK;
556 for (i = 0; i < npstates; ++i) {
557 if ((pstates[i].st_sval & INTEL_MSR_PERF_MASK) == sval)
558 return &pstates[i];
559 }
560 }
561 return NULL;
562}
563
564static int
565acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS *gas)
566{
567 int asz;
568
569 if (gas->AccessWidth != 0)
570 asz = gas->AccessWidth;
571 else
572 asz = gas->BitWidth / NBBY;
573 switch (asz) {
574 case 1:
575 case 2:
576 case 4:
577 break;
578 default:
579 asz = 0;
580 break;
581 }
582 return asz;
583}
584
585static int
586acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS *gas)
587{
588 int reg, end, asz;
589
590 if (gas->BitOffset % NBBY != 0)
591 return EINVAL;
592
593 end = gas->BitWidth / NBBY;
594 reg = gas->BitOffset / NBBY;
595
596 if (reg >= end)
597 return EINVAL;
598
599 asz = acpi_pst_md_gas_asz(gas);
600 if (asz == 0)
601 return EINVAL;
602
603 if (reg + asz > end)
604 return EINVAL;
605 return 0;
606}
607
608static uint32_t
609acpi_pst_md_res_read(const struct acpi_pst_res *res)
610{
611 int asz, reg;
612
613 KKASSERT(res->pr_res != NULL);
614 asz = acpi_pst_md_gas_asz(&res->pr_gas);
615 reg = res->pr_gas.BitOffset / NBBY;
616
617 switch (asz) {
618 case 1:
619 return bus_space_read_1(res->pr_bt, res->pr_bh, reg);
620 case 2:
621 return bus_space_read_2(res->pr_bt, res->pr_bh, reg);
622 case 4:
623 return bus_space_read_4(res->pr_bt, res->pr_bh, reg);
624 }
ed20d0e3 625 panic("unsupported access width %d", asz);
e774ca6d
MD
626
627 /* NEVER REACHED */
628 return 0;
629}
630
631static void
632acpi_pst_md_res_write(const struct acpi_pst_res *res, uint32_t val)
633{
634 int asz, reg;
635
636 KKASSERT(res->pr_res != NULL);
637 asz = acpi_pst_md_gas_asz(&res->pr_gas);
638 reg = res->pr_gas.BitOffset / NBBY;
639
640 switch (asz) {
641 case 1:
642 bus_space_write_1(res->pr_bt, res->pr_bh, reg, val);
643 break;
644 case 2:
645 bus_space_write_2(res->pr_bt, res->pr_bh, reg, val);
646 break;
647 case 4:
648 bus_space_write_4(res->pr_bt, res->pr_bh, reg, val);
649 break;
650 default:
ed20d0e3 651 panic("unsupported access width %d", asz);
e774ca6d
MD
652 }
653}