[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 2/2] ioemu: make management of PCI D-states by guest optional



passthrough: make management of PCI D-states by guest optional

Commit 8c771eb6294afc5b3754a9e3de51568d4e5986c2 enables the guest OS
to program D0-D3hot states of the assigned device, however,
D3hot state in some PCI devices causes the failure of domain 
creation/destruction.

Signed-off-by: Kouya Shimura <kouya@xxxxxxxxxxxxxx>

diff --git a/hw/pass-through.c b/hw/pass-through.c
index 4a86309..522eb73 100644
--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -105,6 +105,9 @@ static int pt_long_reg_read(struct pt_dev *ptdev,
 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);
@@ -407,7 +410,7 @@ static struct pt_reg_info_tbl pt_emu_reg_pm_tbl[] = {
         .ro_mask    = 0xE1FC,
         .emu_mask   = 0x8100,
         .init       = pt_pmcsr_reg_init,
-        .u.w.read   = pt_word_reg_read,
+        .u.w.read   = pt_pmcsr_reg_read,
         .u.w.write  = pt_pmcsr_reg_write,
         .u.w.restore  = pt_pmcsr_reg_restore,
     },
@@ -2341,6 +2344,9 @@ static uint32_t pt_pmc_reg_init(struct pt_dev *ptdev,
 {
     PCIDevice *d = &ptdev->dev;
 
+    if (!ptdev->power_mgmt)
+        return reg->init_val;
+
     /* set Power Management Capabilities register */
     ptdev->pm_state->pmc_field = *(uint16_t *)(d->config + real_offset);
 
@@ -2354,6 +2360,9 @@ static uint32_t pt_pmcsr_reg_init(struct pt_dev *ptdev,
     PCIDevice *d = &ptdev->dev;
     uint16_t cap_ver  = 0;
 
+    if (!ptdev->power_mgmt)
+        return reg->init_val;
+
     /* check PCI Power Management support version */
     cap_ver = ptdev->pm_state->pmc_field & PCI_PM_CAP_VER_MASK;
 
@@ -2553,6 +2562,9 @@ static uint8_t pt_reg_grp_size_init(struct pt_dev *ptdev,
 static uint8_t pt_pm_size_init(struct pt_dev *ptdev,
         struct pt_reg_grp_info_tbl *grp_reg, uint32_t base_offset)
 {
+    if (!ptdev->power_mgmt)
+        return grp_reg->grp_size;
+
     ptdev->pm_state = qemu_mallocz(sizeof(struct pt_pm_info));
     if (!ptdev->pm_state)
     {
@@ -2806,6 +2818,25 @@ static int pt_bar_reg_read(struct pt_dev *ptdev,
    return 0;
 }
 
+
+/* 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;
+
+    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,
@@ -3082,6 +3113,24 @@ static int pt_pmcsr_reg_write(struct pt_dev *ptdev,
     struct pt_pm_info *pm_state = ptdev->pm_state;
     uint16_t read_val = 0;
 
+    if (!ptdev->power_mgmt) {
+        uint16_t emu_mask = 
+            PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_DATA_SCALE_MASK |
+            PCI_PM_CTRL_PME_ENABLE |
+            PCI_PM_CTRL_DATA_SEL_MASK | PCI_PM_CTRL_STATE_MASK;
+        uint16_t ro_mask = PCI_PM_CTRL_DATA_SCALE_MASK;
+
+        /* modify emulate register */
+        writable_mask = emu_mask & ~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;
+        *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+
+        return 0;
+    }
+
     /* modify emulate register */
     writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
     cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
@@ -3564,7 +3613,7 @@ struct pt_dev * register_real_device(PCIBus *e_bus,
     struct pci_config_cf8 machine_bdf;
     int free_pci_slot = -1;
     char *key, *val;
-    int msi_translate;
+    int msi_translate, power_mgmt;
 
     PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
         r_bus, r_dev, r_func);
@@ -3597,6 +3646,7 @@ struct pt_dev * register_real_device(PCIBus *e_bus,
     }
 
     msi_translate = direct_pci_msitranslate;
+    power_mgmt = direct_pci_power_mgmt;
     while (opt) {
         if (get_next_keyval(&opt, &key, &val)) {
             PT_LOG("Error: unrecognized PCI assignment option \"%s\"\n", opt);
@@ -3618,6 +3668,21 @@ struct pt_dev * register_real_device(PCIBus *e_bus,
             else
                 PT_LOG("Error: unrecognized value for msitranslate=\n");
         }
+        else if (strcmp(key, "power_mgmt") == 0)
+        {
+            if (strcmp(val, "0") == 0)
+            {
+                PT_LOG("Disable power management\n");
+                power_mgmt = 0;
+            }
+            else if (strcmp(val, "1") == 0)
+            {
+                PT_LOG("Enable power management\n");
+                power_mgmt = 1;
+            }
+            else
+                PT_LOG("Error: unrecognized value for power_mgmt=\n");
+        }
         else
             PT_LOG("Error: unrecognized PCI assignment option \"%s=%s\"\n", 
key, val);
 
@@ -3639,6 +3704,7 @@ struct pt_dev * register_real_device(PCIBus *e_bus,
 
     assigned_device->pci_dev = pci_dev;
     assigned_device->msi_trans_cap = msi_translate;
+    assigned_device->power_mgmt = power_mgmt;
 
     /* Assign device */
     machine_bdf.reg = 0;
diff --git a/hw/pass-through.h b/hw/pass-through.h
index e86d311..b7b5a79 100644
--- a/hw/pass-through.h
+++ b/hw/pass-through.h
@@ -217,6 +217,7 @@ struct pt_dev {
     /* Physical MSI to guest INTx translation when possible */
     int msi_trans_cap;
     int msi_trans_en;
+    int power_mgmt;
     struct pt_pm_info *pm_state;                /* PM virtualization */
 };
 
diff --git a/hw/pci.h b/hw/pci.h
index 2800499..10fa601 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -65,6 +65,7 @@ struct PCIDevice {
 
 extern char direct_pci_str[];
 extern int direct_pci_msitranslate;
+extern int direct_pci_power_mgmt;
 
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
diff --git a/xenstore.c b/xenstore.c
index 928e950..4ee6ceb 100644
--- a/xenstore.c
+++ b/xenstore.c
@@ -303,8 +303,10 @@ const char *xenstore_get_guest_uuid(void)
 
 #define DIRECT_PCI_STR_LEN 512
 #define PT_PCI_MSITRANSLATE_DEFAULT 1
+#define PT_PCI_POWER_MANAGEMENT_DEFAULT 0
 char direct_pci_str[DIRECT_PCI_STR_LEN];
 int direct_pci_msitranslate;
+int direct_pci_power_mgmt;
 void xenstore_parse_domain_config(int hvm_domid)
 {
     char **e_danger = NULL;
@@ -603,15 +605,26 @@ void xenstore_parse_domain_config(int hvm_domid)
 
     /* get the pci pass-through parameter */
     if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/msitranslate",
-                  hvm_domid, pci_devid) == -1)
-        goto out;
+                  hvm_domid, pci_devid) != -1)
+    {
+        free(params);
+        params = xs_read(xsh, XBT_NULL, buf, &len);
+        if (params)
+            direct_pci_msitranslate = atoi(params);
+        else
+            direct_pci_msitranslate = PT_PCI_MSITRANSLATE_DEFAULT;
+    }
 
-    free(params);
-    params = xs_read(xsh, XBT_NULL, buf, &len);
-    if (params)
-        direct_pci_msitranslate = atoi(params);
-    else
-        direct_pci_msitranslate = PT_PCI_MSITRANSLATE_DEFAULT;
+    if (pasprintf(&buf, "/local/domain/0/backend/pci/%u/%u/power_mgmt",
+                  hvm_domid, pci_devid) != -1)
+    {
+        free(params);
+        params = xs_read(xsh, XBT_NULL, buf, &len);
+        if (params)
+            direct_pci_power_mgmt = atoi(params);
+        else
+            direct_pci_power_mgmt = PT_PCI_POWER_MANAGEMENT_DEFAULT;
+    }
 
  out:
     free(danger_type);
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.