return 0;
 }
 EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids);
+
+/*
+ * Per device IOMMU features.
+ */
+bool iommu_dev_has_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (ops && ops->dev_has_feat)
+               return ops->dev_has_feat(dev, feat);
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(iommu_dev_has_feature);
+
+int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (ops && ops->dev_enable_feat)
+               return ops->dev_enable_feat(dev, feat);
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(iommu_dev_enable_feature);
+
+/*
+ * The device drivers should do the necessary cleanups before calling this.
+ * For example, before disabling the aux-domain feature, the device driver
+ * should detach all aux-domains. Otherwise, this will return -EBUSY.
+ */
+int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (ops && ops->dev_disable_feat)
+               return ops->dev_disable_feat(dev, feat);
+
+       return -EBUSY;
+}
+EXPORT_SYMBOL_GPL(iommu_dev_disable_feature);
+
+bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat)
+{
+       const struct iommu_ops *ops = dev->bus->iommu_ops;
+
+       if (ops && ops->dev_feat_enabled)
+               return ops->dev_feat_enabled(dev, feat);
+
+       return false;
+}
+EXPORT_SYMBOL_GPL(iommu_dev_feature_enabled);
+
+/*
+ * Aux-domain specific attach/detach.
+ *
+ * Only works if iommu_dev_feature_enabled(dev, IOMMU_DEV_FEAT_AUX) returns
+ * true. Also, as long as domains are attached to a device through this
+ * interface, any tries to call iommu_attach_device() should fail
+ * (iommu_detach_device() can't fail, so we fail when trying to re-attach).
+ * This should make us safe against a device being attached to a guest as a
+ * whole while there are still pasid users on it (aux and sva).
+ */
+int iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev)
+{
+       int ret = -ENODEV;
+
+       if (domain->ops->aux_attach_dev)
+               ret = domain->ops->aux_attach_dev(domain, dev);
+
+       if (!ret)
+               trace_attach_device_to_domain(dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_aux_attach_device);
+
+void iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev)
+{
+       if (domain->ops->aux_detach_dev) {
+               domain->ops->aux_detach_dev(domain, dev);
+               trace_detach_device_from_domain(dev);
+       }
+}
+EXPORT_SYMBOL_GPL(iommu_aux_detach_device);
+
+int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev)
+{
+       int ret = -ENODEV;
+
+       if (domain->ops->aux_get_pasid)
+               ret = domain->ops->aux_get_pasid(domain, dev);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_aux_get_pasid);
 
        enum iommu_resv_type    type;
 };
 
+/* Per device IOMMU features */
+enum iommu_dev_features {
+       IOMMU_DEV_FEAT_AUX,     /* Aux-domain feature */
+};
+
 #ifdef CONFIG_IOMMU_API
 
 /**
  * @of_xlate: add OF master IDs to iommu grouping
  * @is_attach_deferred: Check if domain attach should be deferred from iommu
  *                      driver init to device driver init (default no)
+ * @dev_has/enable/disable_feat: per device entries to check/enable/disable
+ *                               iommu specific features.
+ * @dev_feat_enabled: check enabled feature
+ * @aux_attach/detach_dev: aux-domain specific attach/detach entries.
+ * @aux_get_pasid: get the pasid given an aux-domain
  * @pgsize_bitmap: bitmap of all possible supported page sizes
  */
 struct iommu_ops {
        int (*of_xlate)(struct device *dev, struct of_phandle_args *args);
        bool (*is_attach_deferred)(struct iommu_domain *domain, struct device *dev);
 
+       /* Per device IOMMU features */
+       bool (*dev_has_feat)(struct device *dev, enum iommu_dev_features f);
+       bool (*dev_feat_enabled)(struct device *dev, enum iommu_dev_features f);
+       int (*dev_enable_feat)(struct device *dev, enum iommu_dev_features f);
+       int (*dev_disable_feat)(struct device *dev, enum iommu_dev_features f);
+
+       /* Aux-domain specific attach/detach entries */
+       int (*aux_attach_dev)(struct iommu_domain *domain, struct device *dev);
+       void (*aux_detach_dev)(struct iommu_domain *domain, struct device *dev);
+       int (*aux_get_pasid)(struct iommu_domain *domain, struct device *dev);
+
        unsigned long pgsize_bitmap;
 };
 
 int iommu_probe_device(struct device *dev);
 void iommu_release_device(struct device *dev);
 
+bool iommu_dev_has_feature(struct device *dev, enum iommu_dev_features f);
+int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features f);
+int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features f);
+bool iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features f);
+int iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev);
+void iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev);
+int iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev);
+
 #else /* CONFIG_IOMMU_API */
 
 struct iommu_ops {};
        return NULL;
 }
 
+static inline bool
+iommu_dev_has_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       return false;
+}
+
+static inline bool
+iommu_dev_feature_enabled(struct device *dev, enum iommu_dev_features feat)
+{
+       return false;
+}
+
+static inline int
+iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       return -ENODEV;
+}
+
+static inline int
+iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
+{
+       return -ENODEV;
+}
+
+static inline int
+iommu_aux_attach_device(struct iommu_domain *domain, struct device *dev)
+{
+       return -ENODEV;
+}
+
+static inline void
+iommu_aux_detach_device(struct iommu_domain *domain, struct device *dev)
+{
+}
+
+static inline int
+iommu_aux_get_pasid(struct iommu_domain *domain, struct device *dev)
+{
+       return -ENODEV;
+}
+
 #endif /* CONFIG_IOMMU_API */
 
 #ifdef CONFIG_IOMMU_DEBUGFS