All of lore.kernel.org
 help / color / mirror / Atom feed
From: Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
To: "xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>
Cc: "Stewart Hildebrand" <stewart.hildebrand@amd.com>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	"Julien Grall" <julien@xen.org>,
	"Volodymyr Babchuk" <Volodymyr_Babchuk@epam.com>,
	"Wei Liu" <wl@xen.org>,
	"Anthony PERARD" <anthony.perard@citrix.com>,
	"Juergen Gross" <jgross@suse.com>,
	"Andrew Cooper" <andrew.cooper3@citrix.com>,
	"George Dunlap" <george.dunlap@citrix.com>,
	"Jan Beulich" <jbeulich@suse.com>, "Paul Durrant" <paul@xen.org>,
	"Roger Pau Monné" <roger.pau@citrix.com>
Subject: [RFC,FUTURE 1/3] domctl/pci: add ability to provide/request a virtual SBDF
Date: Wed, 13 Dec 2023 23:44:57 +0000	[thread overview]
Message-ID: <20231213234345.779722-2-volodymyr_babchuk@epam.com> (raw)
In-Reply-To: <20231213234345.779722-1-volodymyr_babchuk@epam.com>

With CONFIG_HAS_VPCI_GUEST_SUPPORT enabled, hypervisor will assign a
passed-through PCI device to a guest using virtual/guest SBDF
number. Right now hypervisor automatically allocates next free
SBDF. But there are cases mentioned in [1] when user should be able to
control SBDF assigned to the passed-through device.

To enable this, extend assign_device domctl call with optional
parameter virtual_sbdf. When this parameter is set to
XEN_DOMCTL_DEV_SDBF_ANY, hypervisor will act as previously, but it
will return allocated vSBDF back to the toolstack. Alternatively,
toolstack might provide desired vSBDF and hypervisor will try to use
it, if it is free and falls into permitted range.

[1] https://lore.kernel.org/all/d6a58e73-da51-40f1-a2f7-576274945585@xen.org/

Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
---
 tools/libs/ctrl/xc_domain.c   |  1 +
 xen/drivers/passthrough/pci.c | 17 ++++++++++------
 xen/drivers/vpci/vpci.c       | 38 +++++++++++++++++++++++++++--------
 xen/include/public/domctl.h   |  9 ++++++++-
 xen/include/xen/vpci.h        |  4 ++--
 5 files changed, 52 insertions(+), 17 deletions(-)

diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c
index f2d9d14b4d..2405e39517 100644
--- a/tools/libs/ctrl/xc_domain.c
+++ b/tools/libs/ctrl/xc_domain.c
@@ -1505,6 +1505,7 @@ int xc_assign_device(
     domctl.domain = domid;
     domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
     domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
+    domctl.u.assign_device.u.pci.virtual_sbdf = XEN_DOMCTL_DEV_SDBF_ANY;
     domctl.u.assign_device.flags = flags;
 
     return do_domctl(xch, &domctl);
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index a3312fdab2..9ea18c39f4 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -755,7 +755,7 @@ int pci_add_device(u16 seg, u8 bus, u8 devfn,
          * For devices not discovered by Xen during boot, add vPCI handlers
          * when Dom0 first informs Xen about such devices.
          */
-        ret = vpci_assign_device(pdev);
+        ret = vpci_assign_device(pdev, NULL);
         if ( ret )
         {
             list_del(&pdev->domain_list);
@@ -891,7 +891,7 @@ static int deassign_device(struct domain *d, uint16_t seg, uint8_t bus,
     pdev->fault.count = 0;
 
     write_lock(&target->pci_lock);
-    ret = vpci_assign_device(pdev);
+    ret = vpci_assign_device(pdev, NULL);
     write_unlock(&target->pci_lock);
 
  out:
@@ -1154,7 +1154,7 @@ static void __hwdom_init setup_one_hwdom_device(const struct setup_hwdom *ctxt,
               PCI_SLOT(devfn) == PCI_SLOT(pdev->devfn) );
 
     write_lock(&ctxt->d->pci_lock);
-    err = vpci_assign_device(pdev);
+    err = vpci_assign_device(pdev, NULL);
     write_unlock(&ctxt->d->pci_lock);
     if ( err )
         printk(XENLOG_ERR "setup of vPCI for d%d failed: %d\n",
@@ -1461,7 +1461,8 @@ static int device_assigned(u16 seg, u8 bus, u8 devfn)
 }
 
 /* Caller should hold the pcidevs_lock */
-static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
+static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag,
+                         pci_sbdf_t *vsbdf)
 {
     const struct domain_iommu *hd = dom_iommu(d);
     struct pci_dev *pdev;
@@ -1515,7 +1516,7 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
     }
 
     write_lock(&d->pci_lock);
-    rc = vpci_assign_device(pdev);
+    rc = vpci_assign_device(pdev, vsbdf);
     write_unlock(&d->pci_lock);
 
  done:
@@ -1616,6 +1617,7 @@ int iommu_do_pci_domctl(
     u8 bus, devfn;
     int ret = 0;
     uint32_t machine_sbdf;
+    pci_sbdf_t virtual_sbdf;
 
     switch ( domctl->cmd )
     {
@@ -1675,6 +1677,7 @@ int iommu_do_pci_domctl(
             break;
 
         machine_sbdf = domctl->u.assign_device.u.pci.machine_sbdf;
+        virtual_sbdf.sbdf = domctl->u.assign_device.u.pci.virtual_sbdf;
 
         ret = xsm_assign_device(XSM_HOOK, d, machine_sbdf);
         if ( ret )
@@ -1696,11 +1699,13 @@ int iommu_do_pci_domctl(
             }
         }
         else if ( !ret )
-            ret = assign_device(d, seg, bus, devfn, flags);
+            ret = assign_device(d, seg, bus, devfn, flags, &virtual_sbdf);
         pcidevs_unlock();
         if ( ret == -ERESTART )
             ret = hypercall_create_continuation(__HYPERVISOR_domctl,
                                                 "h", u_domctl);
+
+        domctl->u.assign_device.u.pci.virtual_sbdf = virtual_sbdf.sbdf;
         break;
 
     case XEN_DOMCTL_deassign_device:
diff --git a/xen/drivers/vpci/vpci.c b/xen/drivers/vpci/vpci.c
index 7c0b610ccc..12963b77c3 100644
--- a/xen/drivers/vpci/vpci.c
+++ b/xen/drivers/vpci/vpci.c
@@ -37,7 +37,7 @@ extern vpci_register_init_t *const __end_vpci_array[];
 #define NUM_VPCI_INIT (__end_vpci_array - __start_vpci_array)
 
 #ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT
-static int add_virtual_device(struct pci_dev *pdev)
+static int add_virtual_device(struct pci_dev *pdev, pci_sbdf_t *vsbdf)
 {
     struct domain *d = pdev->domain;
     unsigned int new_dev_number;
@@ -57,13 +57,35 @@ static int add_virtual_device(struct pci_dev *pdev)
                  &pdev->sbdf);
         return -EOPNOTSUPP;
     }
-    new_dev_number = find_first_zero_bit(d->vpci_dev_assigned_map,
-                                         VPCI_MAX_VIRT_DEV);
-    if ( new_dev_number == VPCI_MAX_VIRT_DEV )
-        return -ENOSPC;
 
-    __set_bit(new_dev_number, &d->vpci_dev_assigned_map);
+    if ( !vsbdf || vsbdf->sbdf == XEN_DOMCTL_DEV_SDBF_ANY )
+    {
+        new_dev_number = find_first_zero_bit(d->vpci_dev_assigned_map,
+                                             VPCI_MAX_VIRT_DEV);
+        if ( new_dev_number == VPCI_MAX_VIRT_DEV )
+            return -ENOSPC;
 
+        if ( vsbdf )
+            *vsbdf = PCI_SBDF(0, 0, new_dev_number, 0);
+    }
+    else
+    {
+        if ( vsbdf->seg != 0 || vsbdf->bus != 0 || vsbdf->fn != 0 )
+        {
+            gdprintk(XENLOG_ERR,
+                     "vSBDF %pp: segment, bus and function should be 0\n",
+                     vsbdf);
+            return -EOPNOTSUPP;
+        }
+        new_dev_number = vsbdf->dev;
+        if ( test_bit(new_dev_number, &d->vpci_dev_assigned_map) )
+        {
+            gdprintk(XENLOG_ERR, "vSBDF %pp already assigned\n", vsbdf);
+            return -EOPNOTSUPP;
+        }
+    }
+
+    __set_bit(new_dev_number, &d->vpci_dev_assigned_map);
     /*
      * Both segment and bus number are 0:
      *  - we emulate a single host bridge for the guest, e.g. segment 0
@@ -148,7 +170,7 @@ void vpci_deassign_device(struct pci_dev *pdev)
     pdev->vpci = NULL;
 }
 
-int vpci_assign_device(struct pci_dev *pdev)
+int vpci_assign_device(struct pci_dev *pdev, pci_sbdf_t *vsbdf)
 {
     unsigned int i;
     const unsigned long *ro_map;
@@ -176,7 +198,7 @@ int vpci_assign_device(struct pci_dev *pdev)
 
 #ifdef CONFIG_HAS_VPCI_GUEST_SUPPORT
     pdev->vpci->guest_sbdf.sbdf = ~0;
-    rc = add_virtual_device(pdev);
+    rc = add_virtual_device(pdev, vsbdf);
     if ( rc )
         goto out;
 #endif
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index a33f9ec32b..60a59ce378 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -504,7 +504,12 @@ struct xen_domctl_sendtrigger {
 
 
 /* Assign a device to a guest. Sets up IOMMU structures. */
-/* XEN_DOMCTL_assign_device */
+/* XEN_DOMCTL_assign_device
+ * when assigning a PCI device, it is possible to either request
+ * or provide a virtual SBDF. When virtual_sbdf equals to
+ * XEN_DOMCTL_DEV_SDBF_ANY, hypervisor will return allocated
+ * vSBDF back.
+ */
 /*
  * XEN_DOMCTL_test_assign_device: Pass DOMID_INVALID to find out whether the
  * given device is assigned to any DomU at all. Pass a specific domain ID to
@@ -528,6 +533,8 @@ struct xen_domctl_assign_device {
     union {
         struct {
             uint32_t machine_sbdf;   /* machine PCI ID of assigned device */
+            uint32_t virtual_sbdf;   /* IN/OUT virtual SBDF of the device */
+#define XEN_DOMCTL_DEV_SDBF_ANY     0xFFFFFFFF /* request a free SBDF */
         } pci;
         struct {
             uint32_t size; /* Length of the path */
diff --git a/xen/include/xen/vpci.h b/xen/include/xen/vpci.h
index ec6598237b..f66a641e4f 100644
--- a/xen/include/xen/vpci.h
+++ b/xen/include/xen/vpci.h
@@ -33,7 +33,7 @@ typedef int vpci_register_init_t(struct pci_dev *dev);
                __used_section(".data.vpci." p) = x
 
 /* Assign vPCI to device by adding handlers to device. */
-int __must_check vpci_assign_device(struct pci_dev *pdev);
+int __must_check vpci_assign_device(struct pci_dev *pdev, pci_sbdf_t *vsbdf);
 
 /* Remove all handlers and free vpci related structures. */
 void vpci_deassign_device(struct pci_dev *pdev);
@@ -265,7 +265,7 @@ bool vpci_ecam_read(pci_sbdf_t sbdf, unsigned int reg, unsigned int len,
 #else /* !CONFIG_HAS_VPCI */
 struct vpci_vcpu {};
 
-static inline int vpci_assign_device(struct pci_dev *pdev)
+static inline int vpci_assign_device(struct pci_dev *pdev, pci_sbdf_t *vsbdf)
 {
     return 0;
 }
-- 
2.43.0


  reply	other threads:[~2023-12-13 23:45 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-13 23:44 [RFC,FUTURE 0/3] Make vSBDF configurable by toolstack Volodymyr Babchuk
2023-12-13 23:44 ` Volodymyr Babchuk [this message]
2024-04-22 15:28   ` [RFC,FUTURE 1/3] domctl/pci: add ability to provide/request a virtual SBDF Jan Beulich
2023-12-13 23:44 ` [RFC,FUTURE 2/3] tools: libxc: add virtual_sbdf parameter to xc_assign_device Volodymyr Babchuk
2023-12-13 23:44 ` [RFC,FUTURE 3/3] tools: libxl: use "vslot" parameter when assigning a PCI device Volodymyr Babchuk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231213234345.779722-2-volodymyr_babchuk@epam.com \
    --to=volodymyr_babchuk@epam.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=anthony.perard@citrix.com \
    --cc=george.dunlap@citrix.com \
    --cc=jbeulich@suse.com \
    --cc=jgross@suse.com \
    --cc=julien@xen.org \
    --cc=paul@xen.org \
    --cc=roger.pau@citrix.com \
    --cc=sstabellini@kernel.org \
    --cc=stewart.hildebrand@amd.com \
    --cc=wl@xen.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.