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