@@ -41,6 +41,16 @@ static int vpci_mmio_read(struct vcpu *v, mmio_info_t *info,
/* data is needed to prevent a pointer cast on 32bit */
unsigned long data;
+ /*
+ * For the passed through devices we need to map their virtual SBDF
+ * to the physical PCI device being passed through.
+ */
+ if ( !bridge && !vpci_translate_virtual_device(v->domain, &sbdf) )
+ {
+ *r = ~0ul;
+ return 1;
+ }
+
if ( vpci_ecam_read(sbdf, ECAM_REG_OFFSET(info->gpa),
1U << info->dabt.size, &data) )
{
@@ -59,6 +69,13 @@ static int vpci_mmio_write(struct vcpu *v, mmio_info_t *info,
struct pci_host_bridge *bridge = p;
pci_sbdf_t sbdf = vpci_sbdf_from_gpa(bridge, info->gpa);
+ /*
+ * For the passed through devices we need to map their virtual SBDF
+ * to the physical PCI device being passed through.
+ */
+ if ( !bridge && !vpci_translate_virtual_device(v->domain, &sbdf) )
+ return 1;
+
return vpci_ecam_write(sbdf, ECAM_REG_OFFSET(info->gpa),
1U << info->dabt.size, r);
}
@@ -168,6 +168,35 @@ static void vpci_remove_virtual_device(struct domain *d,
pdev->vpci->guest_sbdf.sbdf = ~0;
}
+/*
+ * Find the physical device which is mapped to the virtual device
+ * and translate virtual SBDF to the physical one.
+ */
+bool vpci_translate_virtual_device(const struct domain *d, pci_sbdf_t *sbdf)
+{
+ struct pci_dev *pdev;
+
+ ASSERT(!is_hardware_domain(d));
+
+ for_each_pdev( d, pdev )
+ {
+ bool found;
+
+ spin_lock(&pdev->vpci_lock);
+ found = pdev->vpci && (pdev->vpci->guest_sbdf.sbdf == sbdf->sbdf);
+ spin_unlock(&pdev->vpci_lock);
+
+ if ( found )
+ {
+ /* Replace guest SBDF with the physical one. */
+ *sbdf = pdev->sbdf;
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Notify vPCI that device is assigned to guest. */
int vpci_assign_device(struct domain *d, struct pci_dev *pdev)
{
@@ -271,6 +271,7 @@ static inline bool __must_check vpci_process_pending(struct vcpu *v)
/* Notify vPCI that device is assigned/de-assigned to/from guest. */
int vpci_assign_device(struct domain *d, struct pci_dev *pdev);
void vpci_deassign_device(struct domain *d, struct pci_dev *pdev);
+bool vpci_translate_virtual_device(const struct domain *d, pci_sbdf_t *sbdf);
#else
static inline int vpci_assign_device(struct domain *d, struct pci_dev *pdev)
{
@@ -280,6 +281,12 @@ static inline int vpci_assign_device(struct domain *d, struct pci_dev *pdev)
static inline void vpci_deassign_device(struct domain *d, struct pci_dev *pdev)
{
};
+
+static inline bool vpci_translate_virtual_device(const struct domain *d,
+ pci_sbdf_t *sbdf)
+{
+ return false;
+}
#endif
#endif