@@ -1469,6 +1469,8 @@ static bool arm_smmu_sid_in_range(struct arm_smmu_device *smmu, u32 sid)
}
/* Forward declaration */
static struct arm_smmu_device *arm_smmu_get_by_dev(struct device *dev);
+static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
+ struct device *dev, u32 flag);
static int arm_smmu_add_device(u8 devfn, struct device *dev)
{
@@ -1527,6 +1529,17 @@ static int arm_smmu_add_device(u8 devfn, struct device *dev)
dev_info(dev, "Added master device (SMMUv3 %s StreamIds %u)\n",
dev_name(fwspec->iommu_dev), fwspec->num_ids);
+#ifdef CONFIG_HAS_PCI
+ if ( dev_is_pci(dev) )
+ {
+ struct pci_dev *pdev = dev_to_pci(dev);
+
+ ret = arm_smmu_assign_dev(pdev->domain, devfn, dev, 0);
+ if (ret)
+ goto err_free_master;
+ }
+#endif
+
return 0;
err_free_master:
@@ -2607,6 +2620,31 @@ static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
struct arm_smmu_domain *smmu_domain;
struct arm_smmu_xen_domain *xen_domain = dom_iommu(d)->arch.priv;
+#ifdef CONFIG_HAS_PCI
+ if ( dev_is_pci(dev) && !is_hardware_domain(d) )
+ {
+ struct pci_dev *pdev = dev_to_pci(dev);
+
+ printk(XENLOG_INFO "Assigning device %04x:%02x:%02x.%u to dom%d\n",
+ pdev->seg, pdev->bus, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), d->domain_id);
+
+ /*
+ * XXX What would be the proper behavior? This could happen if
+ * pdev->phantom_stride > 0
+ */
+ if ( devfn != pdev->devfn )
+ return -EOPNOTSUPP;
+
+ list_move(&pdev->domain_list, &d->pdev_list);
+ pdev->domain = d;
+
+ /* dom_io is used as a sentinel for quarantined devices */
+ if ( d == dom_io )
+ return 0;
+ }
+#endif
+
spin_lock(&xen_domain->lock);
/*
@@ -2640,7 +2678,7 @@ out:
return ret;
}
-static int arm_smmu_deassign_dev(struct domain *d, struct device *dev)
+static int arm_smmu_deassign_dev(struct domain *d, uint8_t devfn, struct device *dev)
{
struct iommu_domain *io_domain = arm_smmu_get_domain(d, dev);
struct arm_smmu_xen_domain *xen_domain = dom_iommu(d)->arch.priv;
@@ -2652,6 +2690,28 @@ static int arm_smmu_deassign_dev(struct domain *d, struct device *dev)
return -ESRCH;
}
+#ifdef CONFIG_HAS_PCI
+ if ( dev_is_pci(dev) )
+ {
+ struct pci_dev *pdev = dev_to_pci(dev);
+
+ printk(XENLOG_INFO "Deassigning device %04x:%02x:%02x.%u from dom%d\n",
+ pdev->seg, pdev->bus, PCI_SLOT(devfn),
+ PCI_FUNC(devfn), d->domain_id);
+
+ /*
+ * XXX What would be the proper behavior? This could happen if
+ * pdev->phantom_stride > 0
+ */
+ if ( devfn != pdev->devfn )
+ return -EOPNOTSUPP;
+
+ /* dom_io is used as a sentinel for quarantined devices */
+ if ( d == dom_io )
+ return 0;
+ }
+#endif
+
spin_lock(&xen_domain->lock);
arm_smmu_detach_dev(master);
@@ -2671,13 +2731,13 @@ static int arm_smmu_reassign_dev(struct domain *s, struct domain *t,
int ret = 0;
/* Don't allow remapping on other domain than hwdom */
- if ( t && !is_hardware_domain(t) )
+ if ( t && !is_hardware_domain(t) && (t != dom_io) )
return -EPERM;
if (t == s)
return 0;
- ret = arm_smmu_deassign_dev(s, dev);
+ ret = arm_smmu_deassign_dev(s, devfn, dev);
if (ret)
return ret;