Intel P-State CPU driver: Support ioport control/status registers
[dragonfly.git] / sys / platform / pc32 / acpica5 / acpi_pstate_machdep.c
CommitLineData
7b46b972
SZ
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>
36#include <sys/systm.h>
37#include <sys/globaldata.h>
fb16beda 38
7b46b972 39#include <machine/md_var.h>
fb16beda
SZ
40#include <machine/cpufunc.h>
41#include <machine/cpufreq.h>
964f1c13 42#include <machine/specialreg.h>
7b46b972
SZ
43
44#include "acpi.h"
45#include "acpi_cpu_pstate.h"
46
fb16beda
SZ
47#define AMD_APMI_HWPSTATE 0x80
48
49#define AMD_MSR_PSTATE_CSR_MASK 0x7ULL
32ecb93d
SZ
50#define AMD1X_MSR_PSTATE_CTL 0xc0010062
51#define AMD1X_MSR_PSTATE_ST 0xc0010063
7b46b972 52
fb16beda 53#define AMD_MSR_PSTATE_EN 0x8000000000000000ULL
7b46b972 54
32ecb93d
SZ
55#define AMD10_MSR_PSTATE_START 0xc0010064
56#define AMD10_MSR_PSTATE_COUNT 5
7b46b972 57
fb16beda
SZ
58#define AMD0F_PST_CTL_FID(cval) (((cval) >> 0) & 0x3f)
59#define AMD0F_PST_CTL_VID(cval) (((cval) >> 6) & 0x1f)
60#define AMD0F_PST_CTL_VST(cval) (((cval) >> 11) & 0x7f)
61#define AMD0F_PST_CTL_MVS(cval) (((cval) >> 18) & 0x3)
62#define AMD0F_PST_CTL_PLLTIME(cval) (((cval) >> 20) & 0x7f)
63#define AMD0F_PST_CTL_RVO(cval) (((cval) >> 28) & 0x3)
64#define AMD0F_PST_CTL_IRT(cval) (((cval) >> 30) & 0x3)
65
66#define AMD0F_PST_ST_FID(sval) (((sval) >> 0) & 0x3f)
67#define AMD0F_PST_ST_VID(sval) (((sval) >> 6) & 0x3f)
7b46b972 68
964f1c13
SZ
69#define INTEL_MSR_MISC_ENABLE 0x1a0
70#define INTEL_MSR_MISC_EST_EN 0x10000ULL
71
72#define INTEL_MSR_PERF_STATUS 0x198
73#define INTEL_MSR_PERF_CTL 0x199
74#define INTEL_MSR_PERF_MASK 0xffffULL
75
7b46b972
SZ
76static const struct acpi_pst_md *
77 acpi_pst_amd_probe(void);
76418417
SZ
78static int acpi_pst_amd_check_csr(const struct acpi_pst_res *,
79 const struct acpi_pst_res *);
d22484e5 80static int acpi_pst_amd1x_check_pstates(const struct acpi_pstate *, int,
7b46b972 81 uint32_t, uint32_t);
d22484e5 82static int acpi_pst_amd10_check_pstates(const struct acpi_pstate *, int);
fb16beda 83static int acpi_pst_amd0f_check_pstates(const struct acpi_pstate *, int);
c5479e60
SZ
84static int acpi_pst_amd_init(const struct acpi_pst_res *,
85 const struct acpi_pst_res *);
76418417
SZ
86static int acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *,
87 const struct acpi_pst_res *, const struct acpi_pstate *);
88static int acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *,
89 const struct acpi_pst_res *, const struct acpi_pstate *);
7b46b972 90static const struct acpi_pstate *
76418417 91 acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *,
7b46b972 92 const struct acpi_pstate *, int);
fb16beda 93static const struct acpi_pstate *
76418417 94 acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *,
fb16beda 95 const struct acpi_pstate *, int);
7b46b972 96
964f1c13
SZ
97static const struct acpi_pst_md *
98 acpi_pst_intel_probe(void);
99static int acpi_pst_intel_check_csr(const struct acpi_pst_res *,
100 const struct acpi_pst_res *);
101static int acpi_pst_intel_check_pstates(const struct acpi_pstate *, int);
102static int acpi_pst_intel_init(const struct acpi_pst_res *,
103 const struct acpi_pst_res *);
104static int acpi_pst_intel_set_pstate(const struct acpi_pst_res *,
105 const struct acpi_pst_res *, const struct acpi_pstate *);
106static const struct acpi_pstate *
107 acpi_pst_intel_get_pstate(const struct acpi_pst_res *,
108 const struct acpi_pstate *, int);
109
df18fa0f
SZ
110static int acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS *);
111static int acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS *);
112static uint32_t acpi_pst_md_res_read(const struct acpi_pst_res *);
113static void acpi_pst_md_res_write(const struct acpi_pst_res *, uint32_t);
114
32ecb93d 115static const struct acpi_pst_md acpi_pst_amd10 = {
7b46b972 116 .pmd_check_csr = acpi_pst_amd_check_csr,
d22484e5 117 .pmd_check_pstates = acpi_pst_amd10_check_pstates,
c5479e60 118 .pmd_init = acpi_pst_amd_init,
d22484e5
SZ
119 .pmd_set_pstate = acpi_pst_amd1x_set_pstate,
120 .pmd_get_pstate = acpi_pst_amd1x_get_pstate
7b46b972
SZ
121};
122
32ecb93d 123static const struct acpi_pst_md acpi_pst_amd0f = {
fb16beda
SZ
124 .pmd_check_csr = acpi_pst_amd_check_csr,
125 .pmd_check_pstates = acpi_pst_amd0f_check_pstates,
c5479e60 126 .pmd_init = acpi_pst_amd_init,
fb16beda
SZ
127 .pmd_set_pstate = acpi_pst_amd0f_set_pstate,
128 .pmd_get_pstate = acpi_pst_amd0f_get_pstate
129};
130
964f1c13
SZ
131static const struct acpi_pst_md acpi_pst_intel = {
132 .pmd_check_csr = acpi_pst_intel_check_csr,
133 .pmd_check_pstates = acpi_pst_intel_check_pstates,
134 .pmd_init = acpi_pst_intel_init,
135 .pmd_set_pstate = acpi_pst_intel_set_pstate,
136 .pmd_get_pstate = acpi_pst_intel_get_pstate
137};
138
7b46b972
SZ
139const struct acpi_pst_md *
140acpi_pst_md_probe(void)
141{
142 if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
143 return acpi_pst_amd_probe();
964f1c13
SZ
144 else if (strcmp(cpu_vendor, "GenuineIntel") == 0)
145 return acpi_pst_intel_probe();
7b46b972
SZ
146 return NULL;
147}
148
149static const struct acpi_pst_md *
150acpi_pst_amd_probe(void)
151{
152 uint32_t regs[4], ext_family;
153
154 if ((cpu_id & 0x00000f00) != 0x00000f00)
155 return NULL;
156
157 /* Check whether APMI exists */
158 do_cpuid(0x80000000, regs);
159 if (regs[0] < 0x80000007)
160 return NULL;
161
162 /* Fetch APMI */
163 do_cpuid(0x80000007, regs);
164
165 ext_family = cpu_id & 0x0ff00000;
166 switch (ext_family) {
fb16beda
SZ
167 case 0x00000000: /* Family 0fh */
168 if ((regs[3] & 0x06) == 0x06)
32ecb93d 169 return &acpi_pst_amd0f;
fb16beda
SZ
170 break;
171
7b46b972
SZ
172 case 0x00100000: /* Family 10h */
173 if (regs[3] & 0x80)
32ecb93d 174 return &acpi_pst_amd10;
7b46b972
SZ
175 break;
176
177 default:
178 break;
179 }
180 return NULL;
181}
182
183static int
76418417
SZ
184acpi_pst_amd_check_csr(const struct acpi_pst_res *ctrl,
185 const struct acpi_pst_res *status)
7b46b972 186{
76418417 187 if (ctrl->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
7b46b972
SZ
188 kprintf("cpu%d: Invalid P-State control register\n", mycpuid);
189 return EINVAL;
190 }
76418417 191 if (status->pr_gas.SpaceId != ACPI_ADR_SPACE_FIXED_HARDWARE) {
7b46b972
SZ
192 kprintf("cpu%d: Invalid P-State status register\n", mycpuid);
193 return EINVAL;
194 }
195 return 0;
196}
197
198static int
d22484e5
SZ
199acpi_pst_amd1x_check_pstates(const struct acpi_pstate *pstates, int npstates,
200 uint32_t msr_start, uint32_t msr_end)
7b46b972
SZ
201{
202 int i;
203
204 /*
205 * Make sure that related MSR P-State registers are enabled.
206 *
207 * NOTE:
208 * We don't check status register value here;
209 * it will not be used.
210 */
211 for (i = 0; i < npstates; ++i) {
212 uint64_t pstate;
213 uint32_t msr;
214
215 msr = msr_start +
216 (pstates[i].st_cval & AMD_MSR_PSTATE_CSR_MASK);
217 if (msr >= msr_end) {
218 kprintf("cpu%d: MSR P-State register %#08x "
219 "does not exist\n", mycpuid, msr);
220 return EINVAL;
221 }
222
223 pstate = rdmsr(msr);
224 if ((pstate & AMD_MSR_PSTATE_EN) == 0) {
225 kprintf("cpu%d: MSR P-State register %#08x "
226 "is not enabled\n", mycpuid, msr);
227 return EINVAL;
228 }
229 }
230 return 0;
231}
232
233static int
d22484e5 234acpi_pst_amd10_check_pstates(const struct acpi_pstate *pstates, int npstates)
7b46b972
SZ
235{
236 /* Only P0-P4 are supported */
32ecb93d 237 if (npstates > AMD10_MSR_PSTATE_COUNT) {
7b46b972
SZ
238 kprintf("cpu%d: only P0-P4 is allowed\n", mycpuid);
239 return EINVAL;
240 }
241
d22484e5 242 return acpi_pst_amd1x_check_pstates(pstates, npstates,
32ecb93d
SZ
243 AMD10_MSR_PSTATE_START,
244 AMD10_MSR_PSTATE_START + AMD10_MSR_PSTATE_COUNT);
7b46b972
SZ
245}
246
247static int
76418417
SZ
248acpi_pst_amd1x_set_pstate(const struct acpi_pst_res *ctrl __unused,
249 const struct acpi_pst_res *status __unused,
d22484e5 250 const struct acpi_pstate *pstate)
7b46b972
SZ
251{
252 uint64_t cval;
253
254 cval = pstate->st_cval & AMD_MSR_PSTATE_CSR_MASK;
32ecb93d 255 wrmsr(AMD1X_MSR_PSTATE_CTL, cval);
7b46b972
SZ
256
257 /*
32ecb93d 258 * Don't check AMD1X_MSR_PSTATE_ST here, since it is
7b46b972
SZ
259 * affected by various P-State limits.
260 *
261 * For details:
262 * AMD Family 10h Processor BKDG Rev 3.20 (#31116)
263 * 2.4.2.4 P-state Transition Behavior
264 */
265
266 return 0;
267}
268
269static const struct acpi_pstate *
76418417 270acpi_pst_amd1x_get_pstate(const struct acpi_pst_res *status __unused,
d22484e5 271 const struct acpi_pstate *pstates, int npstates)
7b46b972
SZ
272{
273 uint64_t sval;
274 int i;
275
32ecb93d 276 sval = rdmsr(AMD1X_MSR_PSTATE_ST) & AMD_MSR_PSTATE_CSR_MASK;
7b46b972
SZ
277 for (i = 0; i < npstates; ++i) {
278 if ((pstates[i].st_sval & AMD_MSR_PSTATE_CSR_MASK) == sval)
279 return &pstates[i];
280 }
281 return NULL;
282}
fb16beda
SZ
283
284static int
285acpi_pst_amd0f_check_pstates(const struct acpi_pstate *pstates, int npstates)
286{
287 struct amd0f_fidvid fv_max, fv_min;
288 int i;
289
290 amd0f_fidvid_limit(&fv_min, &fv_max);
291
292 for (i = 0; i < npstates; ++i) {
293 const struct acpi_pstate *p = &pstates[i];
294 uint32_t fid, vid, mvs, rvo;
295 int mvs_mv, rvo_mv;
296
297 fid = AMD0F_PST_CTL_FID(p->st_cval);
298 vid = AMD0F_PST_CTL_VID(p->st_cval);
299
300 if (fid > fv_max.fid || fid < fv_min.fid) {
301 kprintf("cpu%d: Invalid FID %#x [%#x, %#x]\n",
302 mycpuid, fid, fv_min.fid, fv_max.fid);
303 return EINVAL;
304 }
305 if (vid < fv_max.vid || vid > fv_min.vid) {
306 kprintf("cpu%d: Invalid VID %#x [%#x, %#x]\n",
307 mycpuid, vid, fv_max.vid, fv_min.fid);
308 return EINVAL;
309 }
310
311 mvs = AMD0F_PST_CTL_MVS(p->st_cval);
312 rvo = AMD0F_PST_CTL_RVO(p->st_cval);
313
314 /* Only 0 is allowed, i.e. 25mV stepping */
315 if (mvs != 0) {
316 kprintf("cpu%d: Invalid MVS %#x\n", mycpuid, mvs);
317 return EINVAL;
318 }
319
320 /* -> mV */
321 mvs_mv = 25 * (1 << mvs);
322 rvo_mv = 25 * rvo;
323 if (rvo_mv % mvs_mv != 0) {
324 kprintf("cpu%d: Invalid MVS/RVO (%#x/%#x)\n",
325 mycpuid, mvs, rvo);
326 return EINVAL;
327 }
328 }
329 return 0;
330}
331
332static int
76418417
SZ
333acpi_pst_amd0f_set_pstate(const struct acpi_pst_res *ctrl __unused,
334 const struct acpi_pst_res *status __unused,
fb16beda
SZ
335 const struct acpi_pstate *pstate)
336{
337 struct amd0f_fidvid fv;
338 struct amd0f_xsit xsit;
339
340 fv.fid = AMD0F_PST_CTL_FID(pstate->st_cval);
341 fv.vid = AMD0F_PST_CTL_VID(pstate->st_cval);
342
343 xsit.rvo = AMD0F_PST_CTL_RVO(pstate->st_cval);
344 xsit.mvs = AMD0F_PST_CTL_MVS(pstate->st_cval);
345 xsit.vst = AMD0F_PST_CTL_VST(pstate->st_cval);
346 xsit.pll_time = AMD0F_PST_CTL_PLLTIME(pstate->st_cval);
347 xsit.irt = AMD0F_PST_CTL_IRT(pstate->st_cval);
348
349 return amd0f_set_fidvid(&fv, &xsit);
350}
351
352static const struct acpi_pstate *
76418417 353acpi_pst_amd0f_get_pstate(const struct acpi_pst_res *status __unused,
fb16beda
SZ
354 const struct acpi_pstate *pstates, int npstates)
355{
356 struct amd0f_fidvid fv;
357 int error, i;
358
359 error = amd0f_get_fidvid(&fv);
360 if (error)
361 return NULL;
362
363 for (i = 0; i < npstates; ++i) {
364 const struct acpi_pstate *p = &pstates[i];
365
366 if (fv.fid == AMD0F_PST_ST_FID(p->st_sval) &&
367 fv.vid == AMD0F_PST_ST_VID(p->st_sval))
368 return p;
369 }
370 return NULL;
371}
c5479e60
SZ
372
373static int
374acpi_pst_amd_init(const struct acpi_pst_res *ctrl __unused,
375 const struct acpi_pst_res *status __unused)
376{
377 return 0;
378}
964f1c13
SZ
379
380static const struct acpi_pst_md *
381acpi_pst_intel_probe(void)
382{
383 uint32_t family;
384
385 if ((cpu_feature2 & CPUID2_EST) == 0)
386 return NULL;
387
388 family = cpu_id & 0xf00;
389 if (family != 0xf00 && family != 0x600)
390 return NULL;
391 return &acpi_pst_intel;
392}
393
394static int
395acpi_pst_intel_check_csr(const struct acpi_pst_res *ctrl,
396 const struct acpi_pst_res *status)
397{
df18fa0f
SZ
398 int error;
399
964f1c13
SZ
400 if (ctrl->pr_gas.SpaceId != status->pr_gas.SpaceId) {
401 kprintf("cpu%d: P-State control(%d)/status(%d) registers have "
402 "different SpaceId", mycpuid,
403 ctrl->pr_gas.SpaceId, status->pr_gas.SpaceId);
404 return EINVAL;
405 }
df18fa0f
SZ
406
407 switch (ctrl->pr_gas.SpaceId) {
408 case ACPI_ADR_SPACE_FIXED_HARDWARE:
409 if (ctrl->pr_res != NULL || status->pr_res != NULL) {
410 /* XXX should panic() */
411 kprintf("cpu%d: Allocated resource for fixed hardware "
412 "registers\n", mycpuid);
413 return EINVAL;
414 }
415 break;
416
417 case ACPI_ADR_SPACE_SYSTEM_IO:
418 if (ctrl->pr_res == NULL) {
419 kprintf("cpu%d: ioport allocation failed for control "
420 "register\n", mycpuid);
421 return ENXIO;
422 }
423 error = acpi_pst_md_gas_verify(&ctrl->pr_gas);
424 if (error) {
425 kprintf("cpu%d: Invalid control register GAS\n",
426 mycpuid);
427 return error;
428 }
429
430 if (status->pr_res == NULL) {
431 kprintf("cpu%d: ioport allocation failed for status "
432 "register\n", mycpuid);
433 return ENXIO;
434 }
435 error = acpi_pst_md_gas_verify(&status->pr_gas);
436 if (error) {
437 kprintf("cpu%d: Invalid status register GAS\n",
438 mycpuid);
439 return error;
440 }
441 break;
442
443 default:
444 kprintf("cpu%d: Invalid P-State control/status register "
445 "SpaceId %d\n", mycpuid, ctrl->pr_gas.SpaceId);
446 return EOPNOTSUPP;
447 }
964f1c13
SZ
448 return 0;
449}
450
451static int
452acpi_pst_intel_check_pstates(const struct acpi_pstate *pstates __unused,
453 int npstates __unused)
454{
455 return 0;
456}
457
458static int
459acpi_pst_intel_init(const struct acpi_pst_res *ctrl __unused,
460 const struct acpi_pst_res *status __unused)
461{
462 uint32_t family, model;
463 uint64_t misc_enable;
464
465 family = cpu_id & 0xf00;
466 if (family == 0xf00) {
467 /* EST enable bit is reserved in INTEL_MSR_MISC_ENABLE */
468 return 0;
469 }
470 KKASSERT(family == 0x600);
471
472 model = ((cpu_id & 0xf0000) >> 12) | ((cpu_id & 0xf0) >> 4);
473 if (model < 0xd) {
474 /* EST enable bit is reserved in INTEL_MSR_MISC_ENABLE */
475 return 0;
476 }
477
478 misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
479 if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
480 misc_enable |= INTEL_MSR_MISC_EST_EN;
481 wrmsr(INTEL_MSR_MISC_ENABLE, misc_enable);
482
483 misc_enable = rdmsr(INTEL_MSR_MISC_ENABLE);
484 if ((misc_enable & INTEL_MSR_MISC_EST_EN) == 0) {
485 kprintf("cpu%d: Can't enable EST\n", mycpuid);
486 return EIO;
487 }
488 }
489 return 0;
490}
491
492static int
493acpi_pst_intel_set_pstate(const struct acpi_pst_res *ctrl,
494 const struct acpi_pst_res *status __unused,
495 const struct acpi_pstate *pstate)
496{
964f1c13 497 if (ctrl->pr_res != NULL) {
df18fa0f
SZ
498 acpi_pst_md_res_write(ctrl, pstate->st_cval);
499 } else {
500 uint64_t ctl;
501
502 ctl = rdmsr(INTEL_MSR_PERF_CTL);
503 ctl &= ~INTEL_MSR_PERF_MASK;
504 ctl |= (pstate->st_cval & INTEL_MSR_PERF_MASK);
505 wrmsr(INTEL_MSR_PERF_CTL, ctl);
964f1c13 506 }
964f1c13
SZ
507 return 0;
508}
509
510static const struct acpi_pstate *
511acpi_pst_intel_get_pstate(const struct acpi_pst_res *status,
512 const struct acpi_pstate *pstates, int npstates)
513{
964f1c13
SZ
514 int i;
515
516 if (status->pr_res != NULL) {
df18fa0f 517 uint32_t st;
964f1c13 518
df18fa0f
SZ
519 st = acpi_pst_md_res_read(status);
520 for (i = 0; i < npstates; ++i) {
521 if (pstates[i].st_sval == st)
522 return &pstates[i];
523 }
524 } else {
525 uint64_t sval;
526
527 sval = rdmsr(INTEL_MSR_PERF_STATUS) & INTEL_MSR_PERF_MASK;
528 for (i = 0; i < npstates; ++i) {
529 if ((pstates[i].st_sval & INTEL_MSR_PERF_MASK) == sval)
530 return &pstates[i];
531 }
964f1c13
SZ
532 }
533 return NULL;
534}
df18fa0f
SZ
535
536static int
537acpi_pst_md_gas_asz(const ACPI_GENERIC_ADDRESS *gas)
538{
539 int asz;
540
541 if (gas->AccessWidth != 0)
542 asz = gas->AccessWidth;
543 else
544 asz = gas->BitWidth / NBBY;
545 switch (asz) {
546 case 1:
547 case 2:
548 case 4:
549 break;
550 default:
551 asz = 0;
552 break;
553 }
554 return asz;
555}
556
557static int
558acpi_pst_md_gas_verify(const ACPI_GENERIC_ADDRESS *gas)
559{
560 int reg, end, asz;
561
562 if (gas->BitOffset % NBBY != 0)
563 return EINVAL;
564
565 end = gas->BitWidth / NBBY;
566 reg = gas->BitOffset / NBBY;
567
568 if (reg >= end)
569 return EINVAL;
570
571 asz = acpi_pst_md_gas_asz(gas);
572 if (asz == 0)
573 return EINVAL;
574
575 if (reg + asz > end)
576 return EINVAL;
577 return 0;
578}
579
580static uint32_t
581acpi_pst_md_res_read(const struct acpi_pst_res *res)
582{
583 int asz, reg;
584
585 KKASSERT(res->pr_res != NULL);
586 asz = acpi_pst_md_gas_asz(&res->pr_gas);
587 reg = res->pr_gas.BitOffset / NBBY;
588
589 switch (asz) {
590 case 1:
591 return bus_space_read_1(res->pr_bt, res->pr_bh, reg);
592 case 2:
593 return bus_space_read_2(res->pr_bt, res->pr_bh, reg);
594 case 4:
595 return bus_space_read_4(res->pr_bt, res->pr_bh, reg);
596 }
597 panic("unsupported access width %d\n", asz);
598
599 /* NEVER REACHED */
600 return 0;
601}
602
603static void
604acpi_pst_md_res_write(const struct acpi_pst_res *res, uint32_t val)
605{
606 int asz, reg;
607
608 KKASSERT(res->pr_res != NULL);
609 asz = acpi_pst_md_gas_asz(&res->pr_gas);
610 reg = res->pr_gas.BitOffset / NBBY;
611
612 switch (asz) {
613 case 1:
614 bus_space_write_1(res->pr_bt, res->pr_bh, reg, val);
615 break;
616 case 2:
617 bus_space_write_2(res->pr_bt, res->pr_bh, reg, val);
618 break;
619 case 4:
620 bus_space_write_4(res->pr_bt, res->pr_bh, reg, val);
621 break;
622 default:
623 panic("unsupported access width %d\n", asz);
624 }
625}