static int pt_bar_reg_read(struct pt_dev *ptdev,
struct pt_reg_tbl *cfg_entry,
uint32_t *value, uint32_t valid_mask);
-static int pt_pmcsr_reg_read(struct pt_dev *ptdev,
- struct pt_reg_tbl *cfg_entry,
- uint16_t *value, uint16_t valid_mask);
static int pt_byte_reg_write(struct pt_dev *ptdev,
struct pt_reg_tbl *cfg_entry,
uint8_t *value, uint8_t dev_value, uint8_t valid_mask);
.u.w.write = pt_word_reg_write,
.u.w.restore = NULL,
},
- /* PCI Power Management Control/Status reg */
+ /* PCI Power Management Control/Status reg (->power_mgmt on) */
{
.offset = PCI_PM_CTRL,
.size = 2,
.ro_mask = 0xE1FC,
.emu_mask = 0x8100,
.init = pt_pmcsr_reg_init,
- .u.w.read = pt_pmcsr_reg_read,
+ .u.w.read = pt_word_reg_read,
+ .u.w.write = pt_pmcsr_reg_write,
+ .u.w.restore = pt_pmcsr_reg_restore,
+ },
+ /* PCI Power Management Control/Status reg (->power_mgmt off) */
+ {
+ .offset = PCI_PM_CTRL,
+ .size = 2,
+ .init_val = 0x0008,
+ .ro_mask = 0xE1FC,
+ .emu_mask = 0x810B,
+ .init = pt_pmcsr_reg_init,
+ .u.w.read = pt_word_reg_read,
.u.w.write = pt_pmcsr_reg_write,
.u.w.restore = pt_pmcsr_reg_restore,
},
return reg->init_val;
}
+/* this function will be called twice (for ->power_mgmt on and off cases) */
/* initialize PCI Power Management Control/Status register */
static uint32_t pt_pmcsr_reg_init(struct pt_dev *ptdev,
struct pt_reg_info_tbl *reg, uint32_t real_offset)
PCIDevice *d = &ptdev->dev;
uint16_t cap_ver = 0;
- if (!ptdev->power_mgmt)
- return reg->init_val;
+ switch (reg->emu_mask & (PCI_PM_CTRL_STATE_MASK |
+ PCI_PM_CTRL_NO_SOFT_RESET))
+ {
+ case 0:
+ if (!ptdev->power_mgmt)
+ return PT_INVALID_REG;
+ break;
+ case PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET:
+ if (!ptdev->power_mgmt)
+ return reg->init_val;
+ return PT_INVALID_REG;
+ default:
+ /* exit I/O emulator */
+ PT_LOG("Internal error: Invalid PMCSR emulation mask %04x."
+ " I/O emulator exit.\n", reg->emu_mask);
+ exit(1);
+ }
/* check PCI Power Management support version */
cap_ver = ptdev->pm_state->pmc_field & PCI_PM_CAP_VER_MASK;
}
-/* read Power Management Control/Status register */
-static int pt_pmcsr_reg_read(struct pt_dev *ptdev,
- struct pt_reg_tbl *cfg_entry,
- uint16_t *value, uint16_t valid_mask)
-{
- struct pt_reg_info_tbl *reg = cfg_entry->reg;
- uint16_t valid_emu_mask = reg->emu_mask;
-
- if (!ptdev->power_mgmt)
- valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
-
- valid_emu_mask = valid_emu_mask & valid_mask ;
- *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
-
- return 0;
-}
-
-
/* write byte size emulate register */
static int pt_byte_reg_write(struct pt_dev *ptdev,
struct pt_reg_tbl *cfg_entry,
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
PCIDevice *d = &ptdev->dev;
- uint16_t emu_mask = reg->emu_mask;
uint16_t writable_mask = 0;
uint16_t throughable_mask = 0;
struct pt_pm_info *pm_state = ptdev->pm_state;
uint16_t read_val = 0;
- if (!ptdev->power_mgmt)
- emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
-
/* modify emulate register */
- writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
+ writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~emu_mask & valid_mask;
+ throughable_mask = ~reg->emu_mask & valid_mask;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
if (!ptdev->power_mgmt)