]> xenbits.xensource.com Git - people/royger/xen.git/commitdiff
xen/vpci: trap access to the list of PCI capabilities vpci_v1 gitlab/vpci_v1
authorRoger Pau Monne <roger.pau@citrix.com>
Tue, 11 Apr 2017 07:41:11 +0000 (08:41 +0100)
committerRoger Pau Monne <roger.pau@citrix.com>
Tue, 11 Apr 2017 09:02:44 +0000 (10:02 +0100)
Add traps to each capability PCI_CAP_LIST_NEXT field in order to mask them on
request.

All capabilities from the device are fetched and stored in an internal list,
that's later used in order to return the next capability to the guest. Note
that this only removes the capability from the linked list as seen by the
guest, but the actual capability structure could still be accessed by the
guest, provided that it's position can be found using another mechanism.
Finally the MSI and MSI-X capabilities are masked until Xen knows how to
properly handle accesses to them.

This should allow a PVH Dom0 to boot on some hardware, provided that the
hardware doesn't require MSI/MSI-X and that there are no SR-IOV devices in the
system, so the panic at the end of the PVH Dom0 build is replaced by a
warning.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
xen/arch/x86/hvm/dom0_build.c
xen/drivers/vpci/Makefile
xen/drivers/vpci/capabilities.c [new file with mode: 0644]
xen/include/xen/vpci.h

index 47600345aba2d66c40106778470aaba5918ce24f..23ab20167e9cb0c7fb51061f395cc374e688f33c 100644 (file)
@@ -1091,7 +1091,7 @@ int __init dom0_construct_pvh(struct domain *d, const module_t *image,
         return rc;
     }
 
-    panic("Building a PVHv2 Dom0 is not yet supported.");
+    printk("WARNING: PVH is an experimental mode with limited functionality\n");
     return 0;
 }
 
index 241467212f8fc5737f6c331cdfd3e6063bbf8819..c3f3085c93825142c021056625012199bbc1d9e8 100644 (file)
@@ -1 +1 @@
-obj-y += vpci.o header.o
+obj-y += vpci.o header.o capabilities.o
diff --git a/xen/drivers/vpci/capabilities.c b/xen/drivers/vpci/capabilities.c
new file mode 100644 (file)
index 0000000..69ecd22
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Generic functionality for handling accesses to the PCI capabilities from
+ * the configuration space.
+ *
+ * Copyright (C) 2017 Citrix Systems R&D
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms and conditions of the GNU General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/sched.h>
+#include <xen/vpci.h>
+
+struct vpci_capability {
+    struct list_head next;
+    uint8_t offset;
+    bool masked;
+};
+
+static int vpci_cap_read(struct pci_dev *dev, unsigned int reg,
+                         union vpci_val *val, void *data)
+{
+    struct vpci_capability *next, *curr = data;
+
+    val->half_word = 0;
+
+    /* Return the position of the next non-masked capability. */
+    while ( (next = list_next_entry(curr, next)) != NULL )
+    {
+        if ( !next->masked )
+        {
+            val->half_word = next->offset;
+            break;
+        }
+        curr = next;
+    }
+
+    return 0;
+}
+static int vpci_cap_write(struct pci_dev *dev, unsigned int reg,
+                          union vpci_val val, void *data)
+{
+    /* Ignored. */
+    return 0;
+}
+
+static int vpci_index_capabilities(struct pci_dev *pdev)
+{
+    uint8_t seg = pdev->seg, bus = pdev->bus;
+    uint8_t slot = PCI_SLOT(pdev->devfn), func = PCI_FUNC(pdev->devfn);
+    uint8_t pos = PCI_CAPABILITY_LIST;
+    uint16_t status;
+    unsigned int max_cap = 48;
+    struct vpci_capability *cap;
+    int rc;
+
+    INIT_LIST_HEAD(&pdev->vpci->cap_list);
+
+    /* Check if device has capabilities. */
+    status = pci_conf_read16(seg, bus, slot, func, PCI_STATUS);
+    if ( (status & PCI_STATUS_CAP_LIST) == 0 )
+        return 0;
+
+    /* Add the root capability pointer. */
+    cap = xzalloc(struct vpci_capability);
+    if ( !cap )
+        return -ENOMEM;
+
+    cap->offset = pos;
+    list_add_tail(&cap->next, &pdev->vpci->cap_list);
+    rc = xen_vpci_add_register(pdev, vpci_cap_read, vpci_cap_write, pos,
+                               1, cap);
+    if ( rc )
+        return rc;
+
+    /*
+     * Iterate over the list of capabilities present in the device, and
+     * add a handler for each pointer to the next item (PCI_CAP_LIST_NEXT).
+     */
+    while ( max_cap-- )
+    {
+        pos = pci_conf_read8(seg, bus, slot, func, pos);
+        if ( pos < 0x40 )
+            break;
+
+        cap = xzalloc(struct vpci_capability);
+        if ( !cap )
+            return -ENOMEM;
+
+        cap->offset = pos;
+        list_add_tail(&cap->next, &pdev->vpci->cap_list);
+        pos += PCI_CAP_LIST_NEXT;
+        rc = xen_vpci_add_register(pdev, vpci_cap_read, vpci_cap_write, pos,
+                                   1, cap);
+        if ( rc )
+            return rc;
+    }
+
+    return 0;
+}
+
+static void vpci_mask_capability(struct pci_dev *pdev, uint8_t cap_id)
+{
+    struct vpci_capability *cap;
+    uint8_t cap_offset;
+
+    cap_offset = pci_find_cap_offset(pdev->seg, pdev->bus,
+                                     PCI_SLOT(pdev->devfn),
+                                     PCI_FUNC(pdev->devfn), cap_id);
+    if ( !cap_offset )
+        return;
+
+    list_for_each_entry ( cap, &pdev->vpci->cap_list, next )
+        if ( cap->offset == cap_offset )
+            cap->masked = true;
+}
+
+static int vpci_capabilities_init(struct pci_dev *pdev)
+{
+    int rc;
+
+    rc = vpci_index_capabilities(pdev);
+    if ( rc )
+        return rc;
+
+    /* Mask MSI and MSI-X capabilities until Xen handles them. */
+    vpci_mask_capability(pdev, PCI_CAP_ID_MSI);
+    vpci_mask_capability(pdev, PCI_CAP_ID_MSIX);
+
+    return 0;
+}
+
+REGISTER_VPCI_INIT(vpci_capabilities_init);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+
index 205d121a9206975aef62eefc5dcbbe8bb0a050f2..944f48d89375830fabc87f2a9161f6ce722477dc 100644 (file)
@@ -68,6 +68,9 @@ struct vpci {
             bool sizing;
         } bars[6];
     } header;
+
+    /* List of capabilities supported by the device. */
+    struct list_head cap_list;
 #endif
 };