xen/pt: consolidate PM capability emu_mask

There's no point in xen_pt_pmcsr_reg_{read,write}() each ORing
PCI_PM_CTRL_STATE_MASK and PCI_PM_CTRL_NO_SOFT_RESET into a local
emu_mask variable - we can have the same effect by setting the field
descriptor's emu_mask member suitably right away. Note that
xen_pt_pmcsr_reg_write() is being retained in order to allow later
patches to be less intrusive.

This is a preparatory patch for XSA-131.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>

Index: xen-4.0.3-testing/tools/ioemu-qemu-xen/hw/pass-through.c
===================================================================
--- xen-4.0.3-testing.orig/tools/ioemu-qemu-xen/hw/pass-through.c
+++ xen-4.0.3-testing/tools/ioemu-qemu-xen/hw/pass-through.c
@@ -178,9 +178,6 @@ static int pt_long_reg_read(struct pt_de
 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);
@@ -475,7 +472,7 @@ static struct pt_reg_info_tbl pt_emu_reg
         .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,
@@ -483,7 +480,19 @@ static struct pt_reg_info_tbl pt_emu_reg
         .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,
     },
@@ -2943,6 +2952,7 @@ static uint32_t pt_pmc_reg_init(struct p
     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)
@@ -2950,8 +2960,23 @@ static uint32_t pt_pmcsr_reg_init(struct
     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;
@@ -3428,24 +3453,6 @@ static int pt_bar_reg_read(struct pt_dev
 }
 
 
-/* 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,
@@ -3781,21 +3788,17 @@ static int pt_pmcsr_reg_write(struct pt_
 {
     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)
