1 /* 2 * PMBus wrapper over SMBus 3 * 4 * Copyright 2021 Google LLC 5 * 6 * SPDX-License-Identifier: GPL-2.0-or-later 7 */ 8 9 #include "qemu/osdep.h" 10 #include <math.h> 11 #include "hw/i2c/pmbus_device.h" 12 #include "migration/vmstate.h" 13 #include "qemu/module.h" 14 #include "qemu/log.h" 15 16 uint16_t pmbus_data2direct_mode(PMBusCoefficients c, uint32_t value) 17 { 18 /* R is usually negative to fit large readings into 16 bits */ 19 uint16_t y = (c.m * value + c.b) * pow(10, c.R); 20 return y; 21 } 22 23 uint32_t pmbus_direct_mode2data(PMBusCoefficients c, uint16_t value) 24 { 25 /* X = (Y * 10^-R - b) / m */ 26 uint32_t x = (value / pow(10, c.R) - c.b) / c.m; 27 return x; 28 } 29 30 uint16_t pmbus_data2linear_mode(uint16_t value, int exp) 31 { 32 /* L = D * 2^(-e) */ 33 if (exp < 0) { 34 return value << (-exp); 35 } 36 return value >> exp; 37 } 38 39 uint16_t pmbus_linear_mode2data(uint16_t value, int exp) 40 { 41 /* D = L * 2^e */ 42 if (exp < 0) { 43 return value >> (-exp); 44 } 45 return value << exp; 46 } 47 48 void pmbus_send(PMBusDevice *pmdev, const uint8_t *data, uint16_t len) 49 { 50 if (pmdev->out_buf_len + len > SMBUS_DATA_MAX_LEN) { 51 qemu_log_mask(LOG_GUEST_ERROR, 52 "PMBus device tried to send too much data"); 53 len = 0; 54 } 55 56 for (int i = len - 1; i >= 0; i--) { 57 pmdev->out_buf[i + pmdev->out_buf_len] = data[len - i - 1]; 58 } 59 pmdev->out_buf_len += len; 60 } 61 62 /* Internal only, convert unsigned ints to the little endian bus */ 63 static void pmbus_send_uint(PMBusDevice *pmdev, uint64_t data, uint8_t size) 64 { 65 uint8_t bytes[8]; 66 g_assert(size <= 8); 67 68 for (int i = 0; i < size; i++) { 69 bytes[i] = data & 0xFF; 70 data = data >> 8; 71 } 72 pmbus_send(pmdev, bytes, size); 73 } 74 75 void pmbus_send8(PMBusDevice *pmdev, uint8_t data) 76 { 77 pmbus_send_uint(pmdev, data, 1); 78 } 79 80 void pmbus_send16(PMBusDevice *pmdev, uint16_t data) 81 { 82 pmbus_send_uint(pmdev, data, 2); 83 } 84 85 void pmbus_send32(PMBusDevice *pmdev, uint32_t data) 86 { 87 pmbus_send_uint(pmdev, data, 4); 88 } 89 90 void pmbus_send64(PMBusDevice *pmdev, uint64_t data) 91 { 92 pmbus_send_uint(pmdev, data, 8); 93 } 94 95 void pmbus_send_string(PMBusDevice *pmdev, const char *data) 96 { 97 if (!data) { 98 qemu_log_mask(LOG_GUEST_ERROR, 99 "%s: %s: uninitialised read from 0x%02x\n", 100 __func__, DEVICE(pmdev)->canonical_path, pmdev->code); 101 return; 102 } 103 104 size_t len = strlen(data); 105 g_assert(len + pmdev->out_buf_len < SMBUS_DATA_MAX_LEN); 106 pmdev->out_buf[len + pmdev->out_buf_len] = len; 107 108 for (int i = len - 1; i >= 0; i--) { 109 pmdev->out_buf[i + pmdev->out_buf_len] = data[len - 1 - i]; 110 } 111 pmdev->out_buf_len += len + 1; 112 } 113 114 uint8_t pmbus_receive_block(PMBusDevice *pmdev, uint8_t *dest, size_t len) 115 { 116 /* dest may contain data from previous writes */ 117 memset(dest, 0, len); 118 119 /* Exclude command code from return value */ 120 pmdev->in_buf++; 121 pmdev->in_buf_len--; 122 123 /* The byte after the command code denotes the length */ 124 uint8_t sent_len = pmdev->in_buf[0]; 125 126 if (sent_len != pmdev->in_buf_len - 1) { 127 qemu_log_mask(LOG_GUEST_ERROR, 128 "%s: length mismatch. Expected %d bytes, got %d bytes\n", 129 __func__, sent_len, pmdev->in_buf_len - 1); 130 } 131 132 /* exclude length byte */ 133 pmdev->in_buf++; 134 pmdev->in_buf_len--; 135 136 if (pmdev->in_buf_len < len) { 137 len = pmdev->in_buf_len; 138 } 139 memcpy(dest, pmdev->in_buf, len); 140 return len; 141 } 142 143 144 static uint64_t pmbus_receive_uint(PMBusDevice *pmdev) 145 { 146 uint64_t ret = 0; 147 148 /* Exclude command code from return value */ 149 pmdev->in_buf++; 150 pmdev->in_buf_len--; 151 152 for (int i = pmdev->in_buf_len - 1; i >= 0; i--) { 153 ret = ret << 8 | pmdev->in_buf[i]; 154 } 155 return ret; 156 } 157 158 uint8_t pmbus_receive8(PMBusDevice *pmdev) 159 { 160 if (pmdev->in_buf_len - 1 != 1) { 161 qemu_log_mask(LOG_GUEST_ERROR, 162 "%s: length mismatch. Expected 1 byte, got %d bytes\n", 163 __func__, pmdev->in_buf_len - 1); 164 } 165 return pmbus_receive_uint(pmdev); 166 } 167 168 uint16_t pmbus_receive16(PMBusDevice *pmdev) 169 { 170 if (pmdev->in_buf_len - 1 != 2) { 171 qemu_log_mask(LOG_GUEST_ERROR, 172 "%s: length mismatch. Expected 2 bytes, got %d bytes\n", 173 __func__, pmdev->in_buf_len - 1); 174 } 175 return pmbus_receive_uint(pmdev); 176 } 177 178 uint32_t pmbus_receive32(PMBusDevice *pmdev) 179 { 180 if (pmdev->in_buf_len - 1 != 4) { 181 qemu_log_mask(LOG_GUEST_ERROR, 182 "%s: length mismatch. Expected 4 bytes, got %d bytes\n", 183 __func__, pmdev->in_buf_len - 1); 184 } 185 return pmbus_receive_uint(pmdev); 186 } 187 188 uint64_t pmbus_receive64(PMBusDevice *pmdev) 189 { 190 if (pmdev->in_buf_len - 1 != 8) { 191 qemu_log_mask(LOG_GUEST_ERROR, 192 "%s: length mismatch. Expected 8 bytes, got %d bytes\n", 193 __func__, pmdev->in_buf_len - 1); 194 } 195 return pmbus_receive_uint(pmdev); 196 } 197 198 static uint8_t pmbus_out_buf_pop(PMBusDevice *pmdev) 199 { 200 if (pmdev->out_buf_len == 0) { 201 qemu_log_mask(LOG_GUEST_ERROR, 202 "%s: tried to read from empty buffer", 203 __func__); 204 return PMBUS_ERR_BYTE; 205 } 206 uint8_t data = pmdev->out_buf[pmdev->out_buf_len - 1]; 207 pmdev->out_buf_len--; 208 return data; 209 } 210 211 static void pmbus_quick_cmd(SMBusDevice *smd, uint8_t read) 212 { 213 PMBusDevice *pmdev = PMBUS_DEVICE(smd); 214 PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev); 215 216 if (pmdc->quick_cmd) { 217 pmdc->quick_cmd(pmdev, read); 218 } 219 } 220 221 static uint8_t pmbus_pages_num(PMBusDevice *pmdev) 222 { 223 const PMBusDeviceClass *k = PMBUS_DEVICE_GET_CLASS(pmdev); 224 225 /* some PMBus devices don't use the PAGE command, so they get 1 page */ 226 return k->device_num_pages ? : 1; 227 } 228 229 static void pmbus_pages_alloc(PMBusDevice *pmdev) 230 { 231 pmdev->num_pages = pmbus_pages_num(pmdev); 232 pmdev->pages = g_new0(PMBusPage, pmdev->num_pages); 233 } 234 235 void pmbus_check_limits(PMBusDevice *pmdev) 236 { 237 for (int i = 0; i < pmdev->num_pages; i++) { 238 if ((pmdev->pages[i].operation & PB_OP_ON) == 0) { 239 continue; /* don't check powered off devices */ 240 } 241 242 if (pmdev->pages[i].read_vout > pmdev->pages[i].vout_ov_fault_limit) { 243 pmdev->pages[i].status_word |= PB_STATUS_VOUT; 244 pmdev->pages[i].status_vout |= PB_STATUS_VOUT_OV_FAULT; 245 } 246 247 if (pmdev->pages[i].read_vout > pmdev->pages[i].vout_ov_warn_limit) { 248 pmdev->pages[i].status_word |= PB_STATUS_VOUT; 249 pmdev->pages[i].status_vout |= PB_STATUS_VOUT_OV_WARN; 250 } 251 252 if (pmdev->pages[i].read_vout < pmdev->pages[i].vout_uv_warn_limit) { 253 pmdev->pages[i].status_word |= PB_STATUS_VOUT; 254 pmdev->pages[i].status_vout |= PB_STATUS_VOUT_UV_WARN; 255 } 256 257 if (pmdev->pages[i].read_vout < pmdev->pages[i].vout_uv_fault_limit) { 258 pmdev->pages[i].status_word |= PB_STATUS_VOUT; 259 pmdev->pages[i].status_vout |= PB_STATUS_VOUT_UV_FAULT; 260 } 261 262 if (pmdev->pages[i].read_vin > pmdev->pages[i].vin_ov_warn_limit) { 263 pmdev->pages[i].status_word |= PB_STATUS_INPUT; 264 pmdev->pages[i].status_input |= PB_STATUS_INPUT_VIN_OV_WARN; 265 } 266 267 if (pmdev->pages[i].read_vin < pmdev->pages[i].vin_uv_warn_limit) { 268 pmdev->pages[i].status_word |= PB_STATUS_INPUT; 269 pmdev->pages[i].status_input |= PB_STATUS_INPUT_VIN_UV_WARN; 270 } 271 272 if (pmdev->pages[i].read_iout > pmdev->pages[i].iout_oc_warn_limit) { 273 pmdev->pages[i].status_word |= PB_STATUS_IOUT_POUT; 274 pmdev->pages[i].status_iout |= PB_STATUS_IOUT_OC_WARN; 275 } 276 277 if (pmdev->pages[i].read_iout > pmdev->pages[i].iout_oc_fault_limit) { 278 pmdev->pages[i].status_word |= PB_STATUS_IOUT_POUT; 279 pmdev->pages[i].status_iout |= PB_STATUS_IOUT_OC_FAULT; 280 } 281 282 if (pmdev->pages[i].read_pin > pmdev->pages[i].pin_op_warn_limit) { 283 pmdev->pages[i].status_word |= PB_STATUS_INPUT; 284 pmdev->pages[i].status_input |= PB_STATUS_INPUT_PIN_OP_WARN; 285 } 286 287 if (pmdev->pages[i].read_temperature_1 288 > pmdev->pages[i].ot_fault_limit) { 289 pmdev->pages[i].status_word |= PB_STATUS_TEMPERATURE; 290 pmdev->pages[i].status_temperature |= PB_STATUS_OT_FAULT; 291 } 292 293 if (pmdev->pages[i].read_temperature_1 294 > pmdev->pages[i].ot_warn_limit) { 295 pmdev->pages[i].status_word |= PB_STATUS_TEMPERATURE; 296 pmdev->pages[i].status_temperature |= PB_STATUS_OT_WARN; 297 } 298 } 299 } 300 301 void pmbus_idle(PMBusDevice *pmdev) 302 { 303 pmdev->code = PMBUS_IDLE_STATE; 304 } 305 306 /* assert the status_cml error upon receipt of malformed command */ 307 static void pmbus_cml_error(PMBusDevice *pmdev) 308 { 309 for (int i = 0; i < pmdev->num_pages; i++) { 310 pmdev->pages[i].status_word |= PMBUS_STATUS_CML; 311 pmdev->pages[i].status_cml |= PB_CML_FAULT_INVALID_CMD; 312 } 313 } 314 315 static uint8_t pmbus_receive_byte(SMBusDevice *smd) 316 { 317 PMBusDevice *pmdev = PMBUS_DEVICE(smd); 318 PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev); 319 uint8_t ret = PMBUS_ERR_BYTE; 320 uint8_t index; 321 322 if (pmdev->out_buf_len != 0) { 323 ret = pmbus_out_buf_pop(pmdev); 324 return ret; 325 } 326 327 /* 328 * Reading from all pages will return the value from page 0, 329 * means that all subsequent commands are to be applied to all output. 330 */ 331 if (pmdev->page == PB_ALL_PAGES) { 332 index = 0; 333 } else if (pmdev->page > pmdev->num_pages - 1) { 334 qemu_log_mask(LOG_GUEST_ERROR, 335 "%s: page %d is out of range\n", 336 __func__, pmdev->page); 337 pmbus_cml_error(pmdev); 338 return PMBUS_ERR_BYTE; 339 } else { 340 index = pmdev->page; 341 } 342 343 switch (pmdev->code) { 344 case PMBUS_PAGE: 345 pmbus_send8(pmdev, pmdev->page); 346 break; 347 348 case PMBUS_OPERATION: /* R/W byte */ 349 pmbus_send8(pmdev, pmdev->pages[index].operation); 350 break; 351 352 case PMBUS_ON_OFF_CONFIG: /* R/W byte */ 353 pmbus_send8(pmdev, pmdev->pages[index].on_off_config); 354 break; 355 356 case PMBUS_PHASE: /* R/W byte */ 357 pmbus_send8(pmdev, pmdev->pages[index].phase); 358 break; 359 360 case PMBUS_WRITE_PROTECT: /* R/W byte */ 361 pmbus_send8(pmdev, pmdev->pages[index].write_protect); 362 break; 363 364 case PMBUS_CAPABILITY: 365 pmbus_send8(pmdev, pmdev->capability); 366 if (pmdev->capability & BIT(7)) { 367 qemu_log_mask(LOG_UNIMP, 368 "%s: PEC is enabled but not yet supported.\n", 369 __func__); 370 } 371 break; 372 373 case PMBUS_VOUT_MODE: /* R/W byte */ 374 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) { 375 pmbus_send8(pmdev, pmdev->pages[index].vout_mode); 376 } else { 377 goto passthough; 378 } 379 break; 380 381 case PMBUS_VOUT_COMMAND: /* R/W word */ 382 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 383 pmbus_send16(pmdev, pmdev->pages[index].vout_command); 384 } else { 385 goto passthough; 386 } 387 break; 388 389 case PMBUS_VOUT_TRIM: /* R/W word */ 390 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 391 pmbus_send16(pmdev, pmdev->pages[index].vout_trim); 392 } else { 393 goto passthough; 394 } 395 break; 396 397 case PMBUS_VOUT_CAL_OFFSET: /* R/W word */ 398 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 399 pmbus_send16(pmdev, pmdev->pages[index].vout_cal_offset); 400 } else { 401 goto passthough; 402 } 403 break; 404 405 case PMBUS_VOUT_MAX: /* R/W word */ 406 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 407 pmbus_send16(pmdev, pmdev->pages[index].vout_max); 408 } else { 409 goto passthough; 410 } 411 break; 412 413 case PMBUS_VOUT_MARGIN_HIGH: /* R/W word */ 414 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) { 415 pmbus_send16(pmdev, pmdev->pages[index].vout_margin_high); 416 } else { 417 goto passthough; 418 } 419 break; 420 421 case PMBUS_VOUT_MARGIN_LOW: /* R/W word */ 422 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) { 423 pmbus_send16(pmdev, pmdev->pages[index].vout_margin_low); 424 } else { 425 goto passthough; 426 } 427 break; 428 429 case PMBUS_VOUT_TRANSITION_RATE: /* R/W word */ 430 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 431 pmbus_send16(pmdev, pmdev->pages[index].vout_transition_rate); 432 } else { 433 goto passthough; 434 } 435 break; 436 437 case PMBUS_VOUT_DROOP: /* R/W word */ 438 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 439 pmbus_send16(pmdev, pmdev->pages[index].vout_droop); 440 } else { 441 goto passthough; 442 } 443 break; 444 445 case PMBUS_VOUT_SCALE_LOOP: /* R/W word */ 446 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 447 pmbus_send16(pmdev, pmdev->pages[index].vout_scale_loop); 448 } else { 449 goto passthough; 450 } 451 break; 452 453 case PMBUS_VOUT_SCALE_MONITOR: /* R/W word */ 454 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 455 pmbus_send16(pmdev, pmdev->pages[index].vout_scale_monitor); 456 } else { 457 goto passthough; 458 } 459 break; 460 461 case PMBUS_VOUT_MIN: /* R/W word */ 462 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) { 463 pmbus_send16(pmdev, pmdev->pages[index].vout_min); 464 } else { 465 goto passthough; 466 } 467 break; 468 469 /* TODO: implement coefficients support */ 470 471 case PMBUS_POUT_MAX: /* R/W word */ 472 if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 473 pmbus_send16(pmdev, pmdev->pages[index].pout_max); 474 } else { 475 goto passthough; 476 } 477 break; 478 479 case PMBUS_VIN_ON: /* R/W word */ 480 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 481 pmbus_send16(pmdev, pmdev->pages[index].vin_on); 482 } else { 483 goto passthough; 484 } 485 break; 486 487 case PMBUS_VIN_OFF: /* R/W word */ 488 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 489 pmbus_send16(pmdev, pmdev->pages[index].vin_off); 490 } else { 491 goto passthough; 492 } 493 break; 494 495 case PMBUS_IOUT_CAL_GAIN: /* R/W word */ 496 if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) { 497 pmbus_send16(pmdev, pmdev->pages[index].iout_cal_gain); 498 } else { 499 goto passthough; 500 } 501 break; 502 503 case PMBUS_FAN_CONFIG_1_2: /* R/W byte */ 504 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 505 pmbus_send8(pmdev, pmdev->pages[index].fan_config_1_2); 506 } else { 507 goto passthough; 508 } 509 break; 510 511 case PMBUS_FAN_COMMAND_1: /* R/W word */ 512 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 513 pmbus_send16(pmdev, pmdev->pages[index].fan_command_1); 514 } else { 515 goto passthough; 516 } 517 break; 518 519 case PMBUS_FAN_COMMAND_2: /* R/W word */ 520 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 521 pmbus_send16(pmdev, pmdev->pages[index].fan_command_2); 522 } else { 523 goto passthough; 524 } 525 break; 526 527 case PMBUS_FAN_CONFIG_3_4: /* R/W byte */ 528 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 529 pmbus_send8(pmdev, pmdev->pages[index].fan_config_3_4); 530 } else { 531 goto passthough; 532 } 533 break; 534 535 case PMBUS_FAN_COMMAND_3: /* R/W word */ 536 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 537 pmbus_send16(pmdev, pmdev->pages[index].fan_command_3); 538 } else { 539 goto passthough; 540 } 541 break; 542 543 case PMBUS_FAN_COMMAND_4: /* R/W word */ 544 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 545 pmbus_send16(pmdev, pmdev->pages[index].fan_command_4); 546 } else { 547 goto passthough; 548 } 549 break; 550 551 case PMBUS_VOUT_OV_FAULT_LIMIT: /* R/W word */ 552 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 553 pmbus_send16(pmdev, pmdev->pages[index].vout_ov_fault_limit); 554 } else { 555 goto passthough; 556 } 557 break; 558 559 case PMBUS_VOUT_OV_FAULT_RESPONSE: /* R/W byte */ 560 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 561 pmbus_send8(pmdev, pmdev->pages[index].vout_ov_fault_response); 562 } else { 563 goto passthough; 564 } 565 break; 566 567 case PMBUS_VOUT_OV_WARN_LIMIT: /* R/W word */ 568 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 569 pmbus_send16(pmdev, pmdev->pages[index].vout_ov_warn_limit); 570 } else { 571 goto passthough; 572 } 573 break; 574 575 case PMBUS_VOUT_UV_WARN_LIMIT: /* R/W word */ 576 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 577 pmbus_send16(pmdev, pmdev->pages[index].vout_uv_warn_limit); 578 } else { 579 goto passthough; 580 } 581 break; 582 583 case PMBUS_VOUT_UV_FAULT_LIMIT: /* R/W word */ 584 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 585 pmbus_send16(pmdev, pmdev->pages[index].vout_uv_fault_limit); 586 } else { 587 goto passthough; 588 } 589 break; 590 591 case PMBUS_VOUT_UV_FAULT_RESPONSE: /* R/W byte */ 592 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 593 pmbus_send8(pmdev, pmdev->pages[index].vout_uv_fault_response); 594 } else { 595 goto passthough; 596 } 597 break; 598 599 case PMBUS_IOUT_OC_FAULT_LIMIT: /* R/W word */ 600 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 601 pmbus_send16(pmdev, pmdev->pages[index].iout_oc_fault_limit); 602 } else { 603 goto passthough; 604 } 605 break; 606 607 case PMBUS_IOUT_OC_FAULT_RESPONSE: /* R/W byte */ 608 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 609 pmbus_send8(pmdev, pmdev->pages[index].iout_oc_fault_response); 610 } else { 611 goto passthough; 612 } 613 break; 614 615 case PMBUS_IOUT_OC_LV_FAULT_LIMIT: /* R/W word */ 616 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 617 pmbus_send16(pmdev, pmdev->pages[index].iout_oc_lv_fault_limit); 618 } else { 619 goto passthough; 620 } 621 break; 622 623 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */ 624 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 625 pmbus_send8(pmdev, pmdev->pages[index].iout_oc_lv_fault_response); 626 } else { 627 goto passthough; 628 } 629 break; 630 631 case PMBUS_IOUT_OC_WARN_LIMIT: /* R/W word */ 632 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 633 pmbus_send16(pmdev, pmdev->pages[index].iout_oc_warn_limit); 634 } else { 635 goto passthough; 636 } 637 break; 638 639 case PMBUS_IOUT_UC_FAULT_LIMIT: /* R/W word */ 640 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 641 pmbus_send16(pmdev, pmdev->pages[index].iout_uc_fault_limit); 642 } else { 643 goto passthough; 644 } 645 break; 646 647 case PMBUS_IOUT_UC_FAULT_RESPONSE: /* R/W byte */ 648 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 649 pmbus_send8(pmdev, pmdev->pages[index].iout_uc_fault_response); 650 } else { 651 goto passthough; 652 } 653 break; 654 655 case PMBUS_OT_FAULT_LIMIT: /* R/W word */ 656 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 657 pmbus_send16(pmdev, pmdev->pages[index].ot_fault_limit); 658 } else { 659 goto passthough; 660 } 661 break; 662 663 case PMBUS_OT_FAULT_RESPONSE: /* R/W byte */ 664 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 665 pmbus_send8(pmdev, pmdev->pages[index].ot_fault_response); 666 } else { 667 goto passthough; 668 } 669 break; 670 671 case PMBUS_OT_WARN_LIMIT: /* R/W word */ 672 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 673 pmbus_send16(pmdev, pmdev->pages[index].ot_warn_limit); 674 } else { 675 goto passthough; 676 } 677 break; 678 679 case PMBUS_UT_WARN_LIMIT: /* R/W word */ 680 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 681 pmbus_send16(pmdev, pmdev->pages[index].ut_warn_limit); 682 } else { 683 goto passthough; 684 } 685 break; 686 687 case PMBUS_UT_FAULT_LIMIT: /* R/W word */ 688 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 689 pmbus_send16(pmdev, pmdev->pages[index].ut_fault_limit); 690 } else { 691 goto passthough; 692 } 693 break; 694 695 case PMBUS_UT_FAULT_RESPONSE: /* R/W byte */ 696 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 697 pmbus_send8(pmdev, pmdev->pages[index].ut_fault_response); 698 } else { 699 goto passthough; 700 } 701 break; 702 703 case PMBUS_VIN_OV_FAULT_LIMIT: /* R/W word */ 704 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 705 pmbus_send16(pmdev, pmdev->pages[index].vin_ov_fault_limit); 706 } else { 707 goto passthough; 708 } 709 break; 710 711 case PMBUS_VIN_OV_FAULT_RESPONSE: /* R/W byte */ 712 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 713 pmbus_send8(pmdev, pmdev->pages[index].vin_ov_fault_response); 714 } else { 715 goto passthough; 716 } 717 break; 718 719 case PMBUS_VIN_OV_WARN_LIMIT: /* R/W word */ 720 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 721 pmbus_send16(pmdev, pmdev->pages[index].vin_ov_warn_limit); 722 } else { 723 goto passthough; 724 } 725 break; 726 727 case PMBUS_VIN_UV_WARN_LIMIT: /* R/W word */ 728 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 729 pmbus_send16(pmdev, pmdev->pages[index].vin_uv_warn_limit); 730 } else { 731 goto passthough; 732 } 733 break; 734 735 case PMBUS_VIN_UV_FAULT_LIMIT: /* R/W word */ 736 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 737 pmbus_send16(pmdev, pmdev->pages[index].vin_uv_fault_limit); 738 } else { 739 goto passthough; 740 } 741 break; 742 743 case PMBUS_VIN_UV_FAULT_RESPONSE: /* R/W byte */ 744 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 745 pmbus_send8(pmdev, pmdev->pages[index].vin_uv_fault_response); 746 } else { 747 goto passthough; 748 } 749 break; 750 751 case PMBUS_IIN_OC_FAULT_LIMIT: /* R/W word */ 752 if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 753 pmbus_send16(pmdev, pmdev->pages[index].iin_oc_fault_limit); 754 } else { 755 goto passthough; 756 } 757 break; 758 759 case PMBUS_IIN_OC_FAULT_RESPONSE: /* R/W byte */ 760 if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 761 pmbus_send8(pmdev, pmdev->pages[index].iin_oc_fault_response); 762 } else { 763 goto passthough; 764 } 765 break; 766 767 case PMBUS_IIN_OC_WARN_LIMIT: /* R/W word */ 768 if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 769 pmbus_send16(pmdev, pmdev->pages[index].iin_oc_warn_limit); 770 } else { 771 goto passthough; 772 } 773 break; 774 775 case PMBUS_POUT_OP_FAULT_LIMIT: /* R/W word */ 776 if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 777 pmbus_send16(pmdev, pmdev->pages[index].pout_op_fault_limit); 778 } else { 779 goto passthough; 780 } 781 break; 782 783 case PMBUS_POUT_OP_FAULT_RESPONSE: /* R/W byte */ 784 if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 785 pmbus_send8(pmdev, pmdev->pages[index].pout_op_fault_response); 786 } else { 787 goto passthough; 788 } 789 break; 790 791 case PMBUS_POUT_OP_WARN_LIMIT: /* R/W word */ 792 if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 793 pmbus_send16(pmdev, pmdev->pages[index].pout_op_warn_limit); 794 } else { 795 goto passthough; 796 } 797 break; 798 799 case PMBUS_PIN_OP_WARN_LIMIT: /* R/W word */ 800 if (pmdev->pages[index].page_flags & PB_HAS_PIN) { 801 pmbus_send16(pmdev, pmdev->pages[index].pin_op_warn_limit); 802 } else { 803 goto passthough; 804 } 805 break; 806 807 case PMBUS_STATUS_BYTE: /* R/W byte */ 808 pmbus_send8(pmdev, pmdev->pages[index].status_word & 0xFF); 809 break; 810 811 case PMBUS_STATUS_WORD: /* R/W word */ 812 pmbus_send16(pmdev, pmdev->pages[index].status_word); 813 break; 814 815 case PMBUS_STATUS_VOUT: /* R/W byte */ 816 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 817 pmbus_send8(pmdev, pmdev->pages[index].status_vout); 818 } else { 819 goto passthough; 820 } 821 break; 822 823 case PMBUS_STATUS_IOUT: /* R/W byte */ 824 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 825 pmbus_send8(pmdev, pmdev->pages[index].status_iout); 826 } else { 827 goto passthough; 828 } 829 break; 830 831 case PMBUS_STATUS_INPUT: /* R/W byte */ 832 if (pmdev->pages[index].page_flags & PB_HAS_VIN || 833 pmdev->pages[index].page_flags & PB_HAS_IIN || 834 pmdev->pages[index].page_flags & PB_HAS_PIN) { 835 pmbus_send8(pmdev, pmdev->pages[index].status_input); 836 } else { 837 goto passthough; 838 } 839 break; 840 841 case PMBUS_STATUS_TEMPERATURE: /* R/W byte */ 842 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 843 pmbus_send8(pmdev, pmdev->pages[index].status_temperature); 844 } else { 845 goto passthough; 846 } 847 break; 848 849 case PMBUS_STATUS_CML: /* R/W byte */ 850 pmbus_send8(pmdev, pmdev->pages[index].status_cml); 851 break; 852 853 case PMBUS_STATUS_OTHER: /* R/W byte */ 854 pmbus_send8(pmdev, pmdev->pages[index].status_other); 855 break; 856 857 case PMBUS_STATUS_MFR_SPECIFIC: /* R/W byte */ 858 pmbus_send8(pmdev, pmdev->pages[index].status_mfr_specific); 859 break; 860 861 case PMBUS_STATUS_FANS_1_2: /* R/W byte */ 862 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 863 pmbus_send8(pmdev, pmdev->pages[index].status_fans_1_2); 864 } else { 865 goto passthough; 866 } 867 break; 868 869 case PMBUS_STATUS_FANS_3_4: /* R/W byte */ 870 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 871 pmbus_send8(pmdev, pmdev->pages[index].status_fans_3_4); 872 } else { 873 goto passthough; 874 } 875 break; 876 877 case PMBUS_READ_EIN: /* Read-Only block 5 bytes */ 878 if (pmdev->pages[index].page_flags & PB_HAS_EIN) { 879 pmbus_send(pmdev, pmdev->pages[index].read_ein, 5); 880 } else { 881 goto passthough; 882 } 883 break; 884 885 case PMBUS_READ_EOUT: /* Read-Only block 5 bytes */ 886 if (pmdev->pages[index].page_flags & PB_HAS_EOUT) { 887 pmbus_send(pmdev, pmdev->pages[index].read_eout, 5); 888 } else { 889 goto passthough; 890 } 891 break; 892 893 case PMBUS_READ_VIN: /* Read-Only word */ 894 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 895 pmbus_send16(pmdev, pmdev->pages[index].read_vin); 896 } else { 897 goto passthough; 898 } 899 break; 900 901 case PMBUS_READ_IIN: /* Read-Only word */ 902 if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 903 pmbus_send16(pmdev, pmdev->pages[index].read_iin); 904 } else { 905 goto passthough; 906 } 907 break; 908 909 case PMBUS_READ_VCAP: /* Read-Only word */ 910 if (pmdev->pages[index].page_flags & PB_HAS_VCAP) { 911 pmbus_send16(pmdev, pmdev->pages[index].read_vcap); 912 } else { 913 goto passthough; 914 } 915 break; 916 917 case PMBUS_READ_VOUT: /* Read-Only word */ 918 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 919 pmbus_send16(pmdev, pmdev->pages[index].read_vout); 920 } else { 921 goto passthough; 922 } 923 break; 924 925 case PMBUS_READ_IOUT: /* Read-Only word */ 926 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 927 pmbus_send16(pmdev, pmdev->pages[index].read_iout); 928 } else { 929 goto passthough; 930 } 931 break; 932 933 case PMBUS_READ_TEMPERATURE_1: /* Read-Only word */ 934 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 935 pmbus_send16(pmdev, pmdev->pages[index].read_temperature_1); 936 } else { 937 goto passthough; 938 } 939 break; 940 941 case PMBUS_READ_TEMPERATURE_2: /* Read-Only word */ 942 if (pmdev->pages[index].page_flags & PB_HAS_TEMP2) { 943 pmbus_send16(pmdev, pmdev->pages[index].read_temperature_2); 944 } else { 945 goto passthough; 946 } 947 break; 948 949 case PMBUS_READ_TEMPERATURE_3: /* Read-Only word */ 950 if (pmdev->pages[index].page_flags & PB_HAS_TEMP3) { 951 pmbus_send16(pmdev, pmdev->pages[index].read_temperature_3); 952 } else { 953 goto passthough; 954 } 955 break; 956 957 case PMBUS_READ_FAN_SPEED_1: /* Read-Only word */ 958 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 959 pmbus_send16(pmdev, pmdev->pages[index].read_fan_speed_1); 960 } else { 961 goto passthough; 962 } 963 break; 964 965 case PMBUS_READ_FAN_SPEED_2: /* Read-Only word */ 966 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 967 pmbus_send16(pmdev, pmdev->pages[index].read_fan_speed_2); 968 } else { 969 goto passthough; 970 } 971 break; 972 973 case PMBUS_READ_FAN_SPEED_3: /* Read-Only word */ 974 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 975 pmbus_send16(pmdev, pmdev->pages[index].read_fan_speed_3); 976 } else { 977 goto passthough; 978 } 979 break; 980 981 case PMBUS_READ_FAN_SPEED_4: /* Read-Only word */ 982 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 983 pmbus_send16(pmdev, pmdev->pages[index].read_fan_speed_4); 984 } else { 985 goto passthough; 986 } 987 break; 988 989 case PMBUS_READ_DUTY_CYCLE: /* Read-Only word */ 990 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 991 pmbus_send16(pmdev, pmdev->pages[index].read_duty_cycle); 992 } else { 993 goto passthough; 994 } 995 break; 996 997 case PMBUS_READ_FREQUENCY: /* Read-Only word */ 998 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 999 pmbus_send16(pmdev, pmdev->pages[index].read_frequency); 1000 } else { 1001 goto passthough; 1002 } 1003 break; 1004 1005 case PMBUS_READ_POUT: /* Read-Only word */ 1006 if (pmdev->pages[index].page_flags & PB_HAS_POUT) { 1007 pmbus_send16(pmdev, pmdev->pages[index].read_pout); 1008 } else { 1009 goto passthough; 1010 } 1011 break; 1012 1013 case PMBUS_READ_PIN: /* Read-Only word */ 1014 if (pmdev->pages[index].page_flags & PB_HAS_PIN) { 1015 pmbus_send16(pmdev, pmdev->pages[index].read_pin); 1016 } else { 1017 goto passthough; 1018 } 1019 break; 1020 1021 case PMBUS_REVISION: /* Read-Only byte */ 1022 pmbus_send8(pmdev, pmdev->pages[index].revision); 1023 break; 1024 1025 case PMBUS_MFR_ID: /* R/W block */ 1026 if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) { 1027 pmbus_send_string(pmdev, pmdev->pages[index].mfr_id); 1028 } else { 1029 goto passthough; 1030 } 1031 break; 1032 1033 case PMBUS_MFR_MODEL: /* R/W block */ 1034 if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) { 1035 pmbus_send_string(pmdev, pmdev->pages[index].mfr_model); 1036 } else { 1037 goto passthough; 1038 } 1039 break; 1040 1041 case PMBUS_MFR_REVISION: /* R/W block */ 1042 if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) { 1043 pmbus_send_string(pmdev, pmdev->pages[index].mfr_revision); 1044 } else { 1045 goto passthough; 1046 } 1047 break; 1048 1049 case PMBUS_MFR_LOCATION: /* R/W block */ 1050 if (pmdev->pages[index].page_flags & PB_HAS_MFR_INFO) { 1051 pmbus_send_string(pmdev, pmdev->pages[index].mfr_location); 1052 } else { 1053 goto passthough; 1054 } 1055 break; 1056 1057 case PMBUS_MFR_VIN_MIN: /* Read-Only word */ 1058 if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) { 1059 pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_min); 1060 } else { 1061 goto passthough; 1062 } 1063 break; 1064 1065 case PMBUS_MFR_VIN_MAX: /* Read-Only word */ 1066 if (pmdev->pages[index].page_flags & PB_HAS_VIN_RATING) { 1067 pmbus_send16(pmdev, pmdev->pages[index].mfr_vin_max); 1068 } else { 1069 goto passthough; 1070 } 1071 break; 1072 1073 case PMBUS_MFR_IIN_MAX: /* Read-Only word */ 1074 if (pmdev->pages[index].page_flags & PB_HAS_IIN_RATING) { 1075 pmbus_send16(pmdev, pmdev->pages[index].mfr_iin_max); 1076 } else { 1077 goto passthough; 1078 } 1079 break; 1080 1081 case PMBUS_MFR_PIN_MAX: /* Read-Only word */ 1082 if (pmdev->pages[index].page_flags & PB_HAS_PIN_RATING) { 1083 pmbus_send16(pmdev, pmdev->pages[index].mfr_pin_max); 1084 } else { 1085 goto passthough; 1086 } 1087 break; 1088 1089 case PMBUS_MFR_VOUT_MIN: /* Read-Only word */ 1090 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) { 1091 pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_min); 1092 } else { 1093 goto passthough; 1094 } 1095 break; 1096 1097 case PMBUS_MFR_VOUT_MAX: /* Read-Only word */ 1098 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) { 1099 pmbus_send16(pmdev, pmdev->pages[index].mfr_vout_max); 1100 } else { 1101 goto passthough; 1102 } 1103 break; 1104 1105 case PMBUS_MFR_IOUT_MAX: /* Read-Only word */ 1106 if (pmdev->pages[index].page_flags & PB_HAS_IOUT_RATING) { 1107 pmbus_send16(pmdev, pmdev->pages[index].mfr_iout_max); 1108 } else { 1109 goto passthough; 1110 } 1111 break; 1112 1113 case PMBUS_MFR_POUT_MAX: /* Read-Only word */ 1114 if (pmdev->pages[index].page_flags & PB_HAS_POUT_RATING) { 1115 pmbus_send16(pmdev, pmdev->pages[index].mfr_pout_max); 1116 } else { 1117 goto passthough; 1118 } 1119 break; 1120 1121 case PMBUS_MFR_MAX_TEMP_1: /* R/W word */ 1122 if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) { 1123 pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_1); 1124 } else { 1125 goto passthough; 1126 } 1127 break; 1128 1129 case PMBUS_MFR_MAX_TEMP_2: /* R/W word */ 1130 if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) { 1131 pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_2); 1132 } else { 1133 goto passthough; 1134 } 1135 break; 1136 1137 case PMBUS_MFR_MAX_TEMP_3: /* R/W word */ 1138 if (pmdev->pages[index].page_flags & PB_HAS_TEMP_RATING) { 1139 pmbus_send16(pmdev, pmdev->pages[index].mfr_max_temp_3); 1140 } else { 1141 goto passthough; 1142 } 1143 break; 1144 1145 case PMBUS_IDLE_STATE: 1146 pmbus_send8(pmdev, PMBUS_ERR_BYTE); 1147 break; 1148 1149 case PMBUS_CLEAR_FAULTS: /* Send Byte */ 1150 case PMBUS_PAGE_PLUS_WRITE: /* Block Write-only */ 1151 case PMBUS_STORE_DEFAULT_ALL: /* Send Byte */ 1152 case PMBUS_RESTORE_DEFAULT_ALL: /* Send Byte */ 1153 case PMBUS_STORE_DEFAULT_CODE: /* Write-only Byte */ 1154 case PMBUS_RESTORE_DEFAULT_CODE: /* Write-only Byte */ 1155 case PMBUS_STORE_USER_ALL: /* Send Byte */ 1156 case PMBUS_RESTORE_USER_ALL: /* Send Byte */ 1157 case PMBUS_STORE_USER_CODE: /* Write-only Byte */ 1158 case PMBUS_RESTORE_USER_CODE: /* Write-only Byte */ 1159 case PMBUS_QUERY: /* Write-Only */ 1160 qemu_log_mask(LOG_GUEST_ERROR, 1161 "%s: reading from write only register 0x%02x\n", 1162 __func__, pmdev->code); 1163 break; 1164 1165 passthough: 1166 default: 1167 /* Pass through read request if not handled */ 1168 if (pmdc->receive_byte) { 1169 ret = pmdc->receive_byte(pmdev); 1170 } 1171 break; 1172 } 1173 1174 if (pmdev->out_buf_len != 0) { 1175 ret = pmbus_out_buf_pop(pmdev); 1176 return ret; 1177 } 1178 1179 return ret; 1180 } 1181 1182 /* 1183 * PMBus clear faults command applies to all status registers, existing faults 1184 * should separately get re-asserted. 1185 */ 1186 static void pmbus_clear_faults(PMBusDevice *pmdev) 1187 { 1188 for (uint8_t i = 0; i < pmdev->num_pages; i++) { 1189 pmdev->pages[i].status_word = 0; 1190 pmdev->pages[i].status_vout = 0; 1191 pmdev->pages[i].status_iout = 0; 1192 pmdev->pages[i].status_input = 0; 1193 pmdev->pages[i].status_temperature = 0; 1194 pmdev->pages[i].status_cml = 0; 1195 pmdev->pages[i].status_other = 0; 1196 pmdev->pages[i].status_mfr_specific = 0; 1197 pmdev->pages[i].status_fans_1_2 = 0; 1198 pmdev->pages[i].status_fans_3_4 = 0; 1199 } 1200 1201 } 1202 1203 /* 1204 * PMBus operation is used to turn On and Off PSUs 1205 * Therefore, default value for the Operation should be PB_OP_ON or 0x80 1206 */ 1207 static void pmbus_operation(PMBusDevice *pmdev) 1208 { 1209 uint8_t index = pmdev->page; 1210 if ((pmdev->pages[index].operation & PB_OP_ON) == 0) { 1211 pmdev->pages[index].read_vout = 0; 1212 pmdev->pages[index].read_iout = 0; 1213 pmdev->pages[index].read_pout = 0; 1214 return; 1215 } 1216 1217 if (pmdev->pages[index].operation & (PB_OP_ON | PB_OP_MARGIN_HIGH)) { 1218 pmdev->pages[index].read_vout = pmdev->pages[index].vout_margin_high; 1219 } 1220 1221 if (pmdev->pages[index].operation & (PB_OP_ON | PB_OP_MARGIN_LOW)) { 1222 pmdev->pages[index].read_vout = pmdev->pages[index].vout_margin_low; 1223 } 1224 pmbus_check_limits(pmdev); 1225 } 1226 1227 static int pmbus_write_data(SMBusDevice *smd, uint8_t *buf, uint8_t len) 1228 { 1229 PMBusDevice *pmdev = PMBUS_DEVICE(smd); 1230 PMBusDeviceClass *pmdc = PMBUS_DEVICE_GET_CLASS(pmdev); 1231 int ret = 0; 1232 uint8_t index; 1233 1234 if (len == 0) { 1235 qemu_log_mask(LOG_GUEST_ERROR, "%s: writing empty data\n", __func__); 1236 return PMBUS_ERR_BYTE; 1237 } 1238 1239 if (!pmdev->pages) { /* allocate memory for pages on first use */ 1240 pmbus_pages_alloc(pmdev); 1241 } 1242 1243 pmdev->in_buf_len = len; 1244 pmdev->in_buf = buf; 1245 1246 pmdev->code = buf[0]; /* PMBus command code */ 1247 1248 if (pmdev->code == PMBUS_CLEAR_FAULTS) { 1249 pmbus_clear_faults(pmdev); 1250 } 1251 1252 if (len == 1) { /* Single length writes are command codes only */ 1253 return 0; 1254 } 1255 1256 if (pmdev->code == PMBUS_PAGE) { 1257 pmdev->page = pmbus_receive8(pmdev); 1258 1259 if (pmdev->page > pmdev->num_pages - 1 && pmdev->page != PB_ALL_PAGES) { 1260 qemu_log_mask(LOG_GUEST_ERROR, 1261 "%s: page %u is out of range\n", 1262 __func__, pmdev->page); 1263 pmdev->page = 0; /* undefined behaviour - reset to page 0 */ 1264 pmbus_cml_error(pmdev); 1265 return PMBUS_ERR_BYTE; 1266 } 1267 return 0; 1268 } 1269 1270 /* loop through all the pages when 0xFF is received */ 1271 if (pmdev->page == PB_ALL_PAGES) { 1272 for (int i = 0; i < pmdev->num_pages; i++) { 1273 pmdev->page = i; 1274 pmbus_write_data(smd, buf, len); 1275 } 1276 pmdev->page = PB_ALL_PAGES; 1277 return 0; 1278 } 1279 1280 index = pmdev->page; 1281 1282 switch (pmdev->code) { 1283 case PMBUS_OPERATION: /* R/W byte */ 1284 pmdev->pages[index].operation = pmbus_receive8(pmdev); 1285 pmbus_operation(pmdev); 1286 break; 1287 1288 case PMBUS_ON_OFF_CONFIG: /* R/W byte */ 1289 pmdev->pages[index].on_off_config = pmbus_receive8(pmdev); 1290 break; 1291 1292 case PMBUS_CLEAR_FAULTS: /* Send Byte */ 1293 pmbus_clear_faults(pmdev); 1294 break; 1295 1296 case PMBUS_PHASE: /* R/W byte */ 1297 pmdev->pages[index].phase = pmbus_receive8(pmdev); 1298 break; 1299 1300 case PMBUS_PAGE_PLUS_WRITE: /* Block Write-only */ 1301 case PMBUS_WRITE_PROTECT: /* R/W byte */ 1302 pmdev->pages[index].write_protect = pmbus_receive8(pmdev); 1303 break; 1304 1305 case PMBUS_VOUT_MODE: /* R/W byte */ 1306 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MODE) { 1307 pmdev->pages[index].vout_mode = pmbus_receive8(pmdev); 1308 } else { 1309 goto passthrough; 1310 } 1311 break; 1312 1313 case PMBUS_VOUT_COMMAND: /* R/W word */ 1314 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1315 pmdev->pages[index].vout_command = pmbus_receive16(pmdev); 1316 } else { 1317 goto passthrough; 1318 } 1319 break; 1320 1321 case PMBUS_VOUT_TRIM: /* R/W word */ 1322 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1323 pmdev->pages[index].vout_trim = pmbus_receive16(pmdev); 1324 } else { 1325 goto passthrough; 1326 } 1327 break; 1328 1329 case PMBUS_VOUT_CAL_OFFSET: /* R/W word */ 1330 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1331 pmdev->pages[index].vout_cal_offset = pmbus_receive16(pmdev); 1332 } else { 1333 goto passthrough; 1334 } 1335 break; 1336 1337 case PMBUS_VOUT_MAX: /* R/W word */ 1338 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1339 pmdev->pages[index].vout_max = pmbus_receive16(pmdev); 1340 } else { 1341 goto passthrough; 1342 } 1343 break; 1344 1345 case PMBUS_VOUT_MARGIN_HIGH: /* R/W word */ 1346 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) { 1347 pmdev->pages[index].vout_margin_high = pmbus_receive16(pmdev); 1348 } else { 1349 goto passthrough; 1350 } 1351 break; 1352 1353 case PMBUS_VOUT_MARGIN_LOW: /* R/W word */ 1354 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_MARGIN) { 1355 pmdev->pages[index].vout_margin_low = pmbus_receive16(pmdev); 1356 } else { 1357 goto passthrough; 1358 } 1359 break; 1360 1361 case PMBUS_VOUT_TRANSITION_RATE: /* R/W word */ 1362 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1363 pmdev->pages[index].vout_transition_rate = pmbus_receive16(pmdev); 1364 } else { 1365 goto passthrough; 1366 } 1367 break; 1368 1369 case PMBUS_VOUT_DROOP: /* R/W word */ 1370 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1371 pmdev->pages[index].vout_droop = pmbus_receive16(pmdev); 1372 } else { 1373 goto passthrough; 1374 } 1375 break; 1376 1377 case PMBUS_VOUT_SCALE_LOOP: /* R/W word */ 1378 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1379 pmdev->pages[index].vout_scale_loop = pmbus_receive16(pmdev); 1380 } else { 1381 goto passthrough; 1382 } 1383 break; 1384 1385 case PMBUS_VOUT_SCALE_MONITOR: /* R/W word */ 1386 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1387 pmdev->pages[index].vout_scale_monitor = pmbus_receive16(pmdev); 1388 } else { 1389 goto passthrough; 1390 } 1391 break; 1392 1393 case PMBUS_VOUT_MIN: /* R/W word */ 1394 if (pmdev->pages[index].page_flags & PB_HAS_VOUT_RATING) { 1395 pmdev->pages[index].vout_min = pmbus_receive16(pmdev); 1396 } else { 1397 goto passthrough; 1398 } 1399 break; 1400 1401 case PMBUS_POUT_MAX: /* R/W word */ 1402 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1403 pmdev->pages[index].pout_max = pmbus_receive16(pmdev); 1404 } else { 1405 goto passthrough; 1406 } 1407 break; 1408 1409 case PMBUS_VIN_ON: /* R/W word */ 1410 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 1411 pmdev->pages[index].vin_on = pmbus_receive16(pmdev); 1412 } else { 1413 goto passthrough; 1414 } 1415 break; 1416 1417 case PMBUS_VIN_OFF: /* R/W word */ 1418 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 1419 pmdev->pages[index].vin_off = pmbus_receive16(pmdev); 1420 } else { 1421 goto passthrough; 1422 } 1423 break; 1424 1425 case PMBUS_IOUT_CAL_GAIN: /* R/W word */ 1426 if (pmdev->pages[index].page_flags & PB_HAS_IOUT_GAIN) { 1427 pmdev->pages[index].iout_cal_gain = pmbus_receive16(pmdev); 1428 } else { 1429 goto passthrough; 1430 } 1431 break; 1432 1433 case PMBUS_FAN_CONFIG_1_2: /* R/W byte */ 1434 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 1435 pmdev->pages[index].fan_config_1_2 = pmbus_receive8(pmdev); 1436 } else { 1437 goto passthrough; 1438 } 1439 break; 1440 1441 case PMBUS_FAN_COMMAND_1: /* R/W word */ 1442 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 1443 pmdev->pages[index].fan_command_1 = pmbus_receive16(pmdev); 1444 } else { 1445 goto passthrough; 1446 } 1447 break; 1448 1449 case PMBUS_FAN_COMMAND_2: /* R/W word */ 1450 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 1451 pmdev->pages[index].fan_command_2 = pmbus_receive16(pmdev); 1452 } else { 1453 goto passthrough; 1454 } 1455 break; 1456 1457 case PMBUS_FAN_CONFIG_3_4: /* R/W byte */ 1458 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 1459 pmdev->pages[index].fan_config_3_4 = pmbus_receive8(pmdev); 1460 } else { 1461 goto passthrough; 1462 } 1463 break; 1464 1465 case PMBUS_FAN_COMMAND_3: /* R/W word */ 1466 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 1467 pmdev->pages[index].fan_command_3 = pmbus_receive16(pmdev); 1468 } else { 1469 goto passthrough; 1470 } 1471 break; 1472 1473 case PMBUS_FAN_COMMAND_4: /* R/W word */ 1474 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 1475 pmdev->pages[index].fan_command_4 = pmbus_receive16(pmdev); 1476 } else { 1477 goto passthrough; 1478 } 1479 break; 1480 1481 case PMBUS_VOUT_OV_FAULT_LIMIT: /* R/W word */ 1482 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1483 pmdev->pages[index].vout_ov_fault_limit = pmbus_receive16(pmdev); 1484 } else { 1485 goto passthrough; 1486 } 1487 break; 1488 1489 case PMBUS_VOUT_OV_FAULT_RESPONSE: /* R/W byte */ 1490 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1491 pmdev->pages[index].vout_ov_fault_response = pmbus_receive8(pmdev); 1492 } else { 1493 goto passthrough; 1494 } 1495 break; 1496 1497 case PMBUS_VOUT_OV_WARN_LIMIT: /* R/W word */ 1498 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1499 pmdev->pages[index].vout_ov_warn_limit = pmbus_receive16(pmdev); 1500 } else { 1501 goto passthrough; 1502 } 1503 break; 1504 1505 case PMBUS_VOUT_UV_WARN_LIMIT: /* R/W word */ 1506 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1507 pmdev->pages[index].vout_uv_warn_limit = pmbus_receive16(pmdev); 1508 } else { 1509 goto passthrough; 1510 } 1511 break; 1512 1513 case PMBUS_VOUT_UV_FAULT_LIMIT: /* R/W word */ 1514 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1515 pmdev->pages[index].vout_uv_fault_limit = pmbus_receive16(pmdev); 1516 } else { 1517 goto passthrough; 1518 } 1519 break; 1520 1521 case PMBUS_VOUT_UV_FAULT_RESPONSE: /* R/W byte */ 1522 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1523 pmdev->pages[index].vout_uv_fault_response = pmbus_receive8(pmdev); 1524 } else { 1525 goto passthrough; 1526 } 1527 break; 1528 1529 case PMBUS_IOUT_OC_FAULT_LIMIT: /* R/W word */ 1530 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 1531 pmdev->pages[index].iout_oc_fault_limit = pmbus_receive16(pmdev); 1532 } else { 1533 goto passthrough; 1534 } 1535 break; 1536 1537 case PMBUS_IOUT_OC_FAULT_RESPONSE: /* R/W byte */ 1538 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 1539 pmdev->pages[index].iout_oc_fault_response = pmbus_receive8(pmdev); 1540 } else { 1541 goto passthrough; 1542 } 1543 break; 1544 1545 case PMBUS_IOUT_OC_LV_FAULT_LIMIT: /* R/W word */ 1546 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 1547 pmdev->pages[index].iout_oc_lv_fault_limit = pmbus_receive16(pmdev); 1548 } else { 1549 goto passthrough; 1550 } 1551 break; 1552 1553 case PMBUS_IOUT_OC_LV_FAULT_RESPONSE: /* R/W byte */ 1554 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 1555 pmdev->pages[index].iout_oc_lv_fault_response 1556 = pmbus_receive8(pmdev); 1557 } else { 1558 goto passthrough; 1559 } 1560 break; 1561 1562 case PMBUS_IOUT_OC_WARN_LIMIT: /* R/W word */ 1563 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 1564 pmdev->pages[index].iout_oc_warn_limit = pmbus_receive16(pmdev); 1565 } else { 1566 goto passthrough; 1567 } 1568 break; 1569 1570 case PMBUS_IOUT_UC_FAULT_LIMIT: /* R/W word */ 1571 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 1572 pmdev->pages[index].iout_uc_fault_limit = pmbus_receive16(pmdev); 1573 } else { 1574 goto passthrough; 1575 } 1576 break; 1577 1578 case PMBUS_IOUT_UC_FAULT_RESPONSE: /* R/W byte */ 1579 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 1580 pmdev->pages[index].iout_uc_fault_response = pmbus_receive8(pmdev); 1581 } else { 1582 goto passthrough; 1583 } 1584 break; 1585 1586 case PMBUS_OT_FAULT_LIMIT: /* R/W word */ 1587 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 1588 pmdev->pages[index].ot_fault_limit = pmbus_receive16(pmdev); 1589 } else { 1590 goto passthrough; 1591 } 1592 break; 1593 1594 case PMBUS_OT_FAULT_RESPONSE: /* R/W byte */ 1595 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 1596 pmdev->pages[index].ot_fault_response = pmbus_receive8(pmdev); 1597 } else { 1598 goto passthrough; 1599 } 1600 break; 1601 1602 case PMBUS_OT_WARN_LIMIT: /* R/W word */ 1603 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 1604 pmdev->pages[index].ot_warn_limit = pmbus_receive16(pmdev); 1605 } else { 1606 goto passthrough; 1607 } 1608 break; 1609 1610 case PMBUS_UT_WARN_LIMIT: /* R/W word */ 1611 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 1612 pmdev->pages[index].ut_warn_limit = pmbus_receive16(pmdev); 1613 } else { 1614 goto passthrough; 1615 } 1616 break; 1617 1618 case PMBUS_UT_FAULT_LIMIT: /* R/W word */ 1619 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 1620 pmdev->pages[index].ut_fault_limit = pmbus_receive16(pmdev); 1621 } else { 1622 goto passthrough; 1623 } 1624 break; 1625 1626 case PMBUS_UT_FAULT_RESPONSE: /* R/W byte */ 1627 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 1628 pmdev->pages[index].ut_fault_response = pmbus_receive8(pmdev); 1629 } else { 1630 goto passthrough; 1631 } 1632 break; 1633 1634 case PMBUS_VIN_OV_FAULT_LIMIT: /* R/W word */ 1635 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 1636 pmdev->pages[index].vin_ov_fault_limit = pmbus_receive16(pmdev); 1637 } else { 1638 goto passthrough; 1639 } 1640 break; 1641 1642 case PMBUS_VIN_OV_FAULT_RESPONSE: /* R/W byte */ 1643 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 1644 pmdev->pages[index].vin_ov_fault_response = pmbus_receive8(pmdev); 1645 } else { 1646 goto passthrough; 1647 } 1648 break; 1649 1650 case PMBUS_VIN_OV_WARN_LIMIT: /* R/W word */ 1651 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 1652 pmdev->pages[index].vin_ov_warn_limit = pmbus_receive16(pmdev); 1653 } else { 1654 goto passthrough; 1655 } 1656 break; 1657 1658 case PMBUS_VIN_UV_WARN_LIMIT: /* R/W word */ 1659 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 1660 pmdev->pages[index].vin_uv_warn_limit = pmbus_receive16(pmdev); 1661 } else { 1662 goto passthrough; 1663 } 1664 break; 1665 1666 case PMBUS_VIN_UV_FAULT_LIMIT: /* R/W word */ 1667 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 1668 pmdev->pages[index].vin_uv_fault_limit = pmbus_receive16(pmdev); 1669 } else { 1670 goto passthrough; 1671 } 1672 break; 1673 1674 case PMBUS_VIN_UV_FAULT_RESPONSE: /* R/W byte */ 1675 if (pmdev->pages[index].page_flags & PB_HAS_VIN) { 1676 pmdev->pages[index].vin_uv_fault_response = pmbus_receive8(pmdev); 1677 } else { 1678 goto passthrough; 1679 } 1680 break; 1681 1682 case PMBUS_IIN_OC_FAULT_LIMIT: /* R/W word */ 1683 if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 1684 pmdev->pages[index].iin_oc_fault_limit = pmbus_receive16(pmdev); 1685 } else { 1686 goto passthrough; 1687 } 1688 break; 1689 1690 case PMBUS_IIN_OC_FAULT_RESPONSE: /* R/W byte */ 1691 if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 1692 pmdev->pages[index].iin_oc_fault_response = pmbus_receive8(pmdev); 1693 } else { 1694 goto passthrough; 1695 } 1696 break; 1697 1698 case PMBUS_IIN_OC_WARN_LIMIT: /* R/W word */ 1699 if (pmdev->pages[index].page_flags & PB_HAS_IIN) { 1700 pmdev->pages[index].iin_oc_warn_limit = pmbus_receive16(pmdev); 1701 } else { 1702 goto passthrough; 1703 } 1704 break; 1705 1706 case PMBUS_POUT_OP_FAULT_LIMIT: /* R/W word */ 1707 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1708 pmdev->pages[index].pout_op_fault_limit = pmbus_receive16(pmdev); 1709 } else { 1710 goto passthrough; 1711 } 1712 break; 1713 1714 case PMBUS_POUT_OP_FAULT_RESPONSE: /* R/W byte */ 1715 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1716 pmdev->pages[index].pout_op_fault_response = pmbus_receive8(pmdev); 1717 } else { 1718 goto passthrough; 1719 } 1720 break; 1721 1722 case PMBUS_POUT_OP_WARN_LIMIT: /* R/W word */ 1723 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1724 pmdev->pages[index].pout_op_warn_limit = pmbus_receive16(pmdev); 1725 } else { 1726 goto passthrough; 1727 } 1728 break; 1729 1730 case PMBUS_PIN_OP_WARN_LIMIT: /* R/W word */ 1731 if (pmdev->pages[index].page_flags & PB_HAS_PIN) { 1732 pmdev->pages[index].pin_op_warn_limit = pmbus_receive16(pmdev); 1733 } else { 1734 goto passthrough; 1735 } 1736 break; 1737 1738 case PMBUS_STATUS_BYTE: /* R/W byte */ 1739 pmdev->pages[index].status_word = pmbus_receive8(pmdev); 1740 break; 1741 1742 case PMBUS_STATUS_WORD: /* R/W word */ 1743 pmdev->pages[index].status_word = pmbus_receive16(pmdev); 1744 break; 1745 1746 case PMBUS_STATUS_VOUT: /* R/W byte */ 1747 if (pmdev->pages[index].page_flags & PB_HAS_VOUT) { 1748 pmdev->pages[index].status_vout = pmbus_receive8(pmdev); 1749 } else { 1750 goto passthrough; 1751 } 1752 break; 1753 1754 case PMBUS_STATUS_IOUT: /* R/W byte */ 1755 if (pmdev->pages[index].page_flags & PB_HAS_IOUT) { 1756 pmdev->pages[index].status_iout = pmbus_receive8(pmdev); 1757 } else { 1758 goto passthrough; 1759 } 1760 break; 1761 1762 case PMBUS_STATUS_INPUT: /* R/W byte */ 1763 pmdev->pages[index].status_input = pmbus_receive8(pmdev); 1764 break; 1765 1766 case PMBUS_STATUS_TEMPERATURE: /* R/W byte */ 1767 if (pmdev->pages[index].page_flags & PB_HAS_TEMPERATURE) { 1768 pmdev->pages[index].status_temperature = pmbus_receive8(pmdev); 1769 } else { 1770 goto passthrough; 1771 } 1772 break; 1773 1774 case PMBUS_STATUS_CML: /* R/W byte */ 1775 pmdev->pages[index].status_cml = pmbus_receive8(pmdev); 1776 break; 1777 1778 case PMBUS_STATUS_OTHER: /* R/W byte */ 1779 pmdev->pages[index].status_other = pmbus_receive8(pmdev); 1780 break; 1781 1782 case PMBUS_STATUS_MFR_SPECIFIC: /* R/W byte */ 1783 pmdev->pages[index].status_mfr_specific = pmbus_receive8(pmdev); 1784 break; 1785 1786 case PMBUS_STATUS_FANS_1_2: /* R/W byte */ 1787 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 1788 pmbus_send8(pmdev, pmdev->pages[index].status_fans_1_2); 1789 } else { 1790 goto passthrough; 1791 } 1792 break; 1793 1794 case PMBUS_STATUS_FANS_3_4: /* R/W byte */ 1795 if (pmdev->pages[index].page_flags & PB_HAS_FAN) { 1796 pmbus_send8(pmdev, pmdev->pages[index].status_fans_3_4); 1797 } else { 1798 goto passthrough; 1799 } 1800 break; 1801 1802 case PMBUS_PAGE_PLUS_READ: /* Block Read-only */ 1803 case PMBUS_CAPABILITY: /* Read-Only byte */ 1804 case PMBUS_COEFFICIENTS: /* Read-only block 5 bytes */ 1805 case PMBUS_READ_EIN: /* Read-Only block 5 bytes */ 1806 case PMBUS_READ_EOUT: /* Read-Only block 5 bytes */ 1807 case PMBUS_READ_VIN: /* Read-Only word */ 1808 case PMBUS_READ_IIN: /* Read-Only word */ 1809 case PMBUS_READ_VCAP: /* Read-Only word */ 1810 case PMBUS_READ_VOUT: /* Read-Only word */ 1811 case PMBUS_READ_IOUT: /* Read-Only word */ 1812 case PMBUS_READ_TEMPERATURE_1: /* Read-Only word */ 1813 case PMBUS_READ_TEMPERATURE_2: /* Read-Only word */ 1814 case PMBUS_READ_TEMPERATURE_3: /* Read-Only word */ 1815 case PMBUS_READ_FAN_SPEED_1: /* Read-Only word */ 1816 case PMBUS_READ_FAN_SPEED_2: /* Read-Only word */ 1817 case PMBUS_READ_FAN_SPEED_3: /* Read-Only word */ 1818 case PMBUS_READ_FAN_SPEED_4: /* Read-Only word */ 1819 case PMBUS_READ_DUTY_CYCLE: /* Read-Only word */ 1820 case PMBUS_READ_FREQUENCY: /* Read-Only word */ 1821 case PMBUS_READ_POUT: /* Read-Only word */ 1822 case PMBUS_READ_PIN: /* Read-Only word */ 1823 case PMBUS_REVISION: /* Read-Only byte */ 1824 case PMBUS_APP_PROFILE_SUPPORT: /* Read-Only block-read */ 1825 case PMBUS_MFR_VIN_MIN: /* Read-Only word */ 1826 case PMBUS_MFR_VIN_MAX: /* Read-Only word */ 1827 case PMBUS_MFR_IIN_MAX: /* Read-Only word */ 1828 case PMBUS_MFR_PIN_MAX: /* Read-Only word */ 1829 case PMBUS_MFR_VOUT_MIN: /* Read-Only word */ 1830 case PMBUS_MFR_VOUT_MAX: /* Read-Only word */ 1831 case PMBUS_MFR_IOUT_MAX: /* Read-Only word */ 1832 case PMBUS_MFR_POUT_MAX: /* Read-Only word */ 1833 case PMBUS_MFR_TAMBIENT_MAX: /* Read-Only word */ 1834 case PMBUS_MFR_TAMBIENT_MIN: /* Read-Only word */ 1835 case PMBUS_MFR_EFFICIENCY_LL: /* Read-Only block 14 bytes */ 1836 case PMBUS_MFR_EFFICIENCY_HL: /* Read-Only block 14 bytes */ 1837 case PMBUS_MFR_PIN_ACCURACY: /* Read-Only byte */ 1838 case PMBUS_IC_DEVICE_ID: /* Read-Only block-read */ 1839 case PMBUS_IC_DEVICE_REV: /* Read-Only block-read */ 1840 qemu_log_mask(LOG_GUEST_ERROR, 1841 "%s: writing to read-only register 0x%02x\n", 1842 __func__, pmdev->code); 1843 break; 1844 1845 passthrough: 1846 /* Unimplemented registers get passed to the device */ 1847 default: 1848 if (pmdc->write_data) { 1849 ret = pmdc->write_data(pmdev, buf, len); 1850 } 1851 break; 1852 } 1853 pmbus_check_limits(pmdev); 1854 pmdev->in_buf_len = 0; 1855 return ret; 1856 } 1857 1858 int pmbus_page_config(PMBusDevice *pmdev, uint8_t index, uint64_t flags) 1859 { 1860 if (!pmdev->pages) { /* allocate memory for pages on first use */ 1861 pmbus_pages_alloc(pmdev); 1862 } 1863 1864 /* The 0xFF page is special for commands applying to all pages */ 1865 if (index == PB_ALL_PAGES) { 1866 for (int i = 0; i < pmdev->num_pages; i++) { 1867 pmdev->pages[i].page_flags = flags; 1868 } 1869 return 0; 1870 } 1871 1872 if (index > pmdev->num_pages - 1) { 1873 qemu_log_mask(LOG_GUEST_ERROR, 1874 "%s: index %u is out of range\n", 1875 __func__, index); 1876 return -1; 1877 } 1878 1879 pmdev->pages[index].page_flags = flags; 1880 1881 return 0; 1882 } 1883 1884 /* TODO: include pmbus page info in vmstate */ 1885 const VMStateDescription vmstate_pmbus_device = { 1886 .name = TYPE_PMBUS_DEVICE, 1887 .version_id = 0, 1888 .minimum_version_id = 0, 1889 .fields = (VMStateField[]) { 1890 VMSTATE_SMBUS_DEVICE(smb, PMBusDevice), 1891 VMSTATE_UINT8(num_pages, PMBusDevice), 1892 VMSTATE_UINT8(code, PMBusDevice), 1893 VMSTATE_UINT8(page, PMBusDevice), 1894 VMSTATE_UINT8(capability, PMBusDevice), 1895 VMSTATE_END_OF_LIST() 1896 } 1897 }; 1898 1899 static void pmbus_device_finalize(Object *obj) 1900 { 1901 PMBusDevice *pmdev = PMBUS_DEVICE(obj); 1902 g_free(pmdev->pages); 1903 } 1904 1905 static void pmbus_device_class_init(ObjectClass *klass, void *data) 1906 { 1907 SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass); 1908 1909 k->quick_cmd = pmbus_quick_cmd; 1910 k->write_data = pmbus_write_data; 1911 k->receive_byte = pmbus_receive_byte; 1912 } 1913 1914 static const TypeInfo pmbus_device_type_info = { 1915 .name = TYPE_PMBUS_DEVICE, 1916 .parent = TYPE_SMBUS_DEVICE, 1917 .instance_size = sizeof(PMBusDevice), 1918 .instance_finalize = pmbus_device_finalize, 1919 .abstract = true, 1920 .class_size = sizeof(PMBusDeviceClass), 1921 .class_init = pmbus_device_class_init, 1922 }; 1923 1924 static void pmbus_device_register_types(void) 1925 { 1926 type_register_static(&pmbus_device_type_info); 1927 } 1928 1929 type_init(pmbus_device_register_types) 1930