Takashi Iwai b96bab
From 42a1b73852c4a176d233a192422b5e1d0ba67cbf Mon Sep 17 00:00:00 2001
Takashi Iwai b96bab
From: Dave Jiang <dave.jiang@intel.com>
Takashi Iwai b96bab
Date: Wed, 11 May 2022 17:11:57 -0700
Takashi Iwai b96bab
Subject: [PATCH] dmaengine: idxd: Separate user and kernel pasid enabling
Takashi Iwai b96bab
Git-commit: 42a1b73852c4a176d233a192422b5e1d0ba67cbf
Takashi Iwai b96bab
Patch-mainline: v5.19-rc1
Takashi Iwai b96bab
References: git-fixes
Takashi Iwai b96bab
Takashi Iwai b96bab
The idxd driver always gated the pasid enabling under a single knob and
Takashi Iwai b96bab
this assumption is incorrect. The pasid used for kernel operation can be
Takashi Iwai b96bab
independently toggled and has no dependency on the user pasid (and vice
Takashi Iwai b96bab
versa). Split the two so they are independent "enabled" flags.
Takashi Iwai b96bab
Takashi Iwai b96bab
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Takashi Iwai b96bab
Link: https://lore.kernel.org/r/165231431746.986466.5666862038354800551.stgit@djiang5-desk3.ch.intel.com
Takashi Iwai b96bab
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Takashi Iwai b96bab
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai b96bab
Takashi Iwai b96bab
---
Takashi Iwai b96bab
 drivers/dma/idxd/cdev.c   |    4 ++--
Takashi Iwai b96bab
 drivers/dma/idxd/device.c |    4 ++--
Takashi Iwai b96bab
 drivers/dma/idxd/idxd.h   |   16 ++++++++++++++--
Takashi Iwai b96bab
 drivers/dma/idxd/init.c   |   30 +++++++++++++++---------------
Takashi Iwai b96bab
 drivers/dma/idxd/sysfs.c  |    2 +-
Takashi Iwai b96bab
 5 files changed, 34 insertions(+), 22 deletions(-)
Takashi Iwai b96bab
Takashi Iwai b96bab
--- a/drivers/dma/idxd/cdev.c
Takashi Iwai b96bab
+++ b/drivers/dma/idxd/cdev.c
Takashi Iwai b96bab
@@ -99,7 +99,7 @@ static int idxd_cdev_open(struct inode *
Takashi Iwai b96bab
 	ctx->wq = wq;
Takashi Iwai b96bab
 	filp->private_data = ctx;
Takashi Iwai b96bab
 
Takashi Iwai b96bab
-	if (device_pasid_enabled(idxd)) {
Takashi Iwai b96bab
+	if (device_user_pasid_enabled(idxd)) {
Takashi Iwai b96bab
 		sva = iommu_sva_bind_device(dev, current->mm, NULL);
Takashi Iwai b96bab
 		if (IS_ERR(sva)) {
Takashi Iwai b96bab
 			rc = PTR_ERR(sva);
Takashi Iwai b96bab
@@ -152,7 +152,7 @@ static int idxd_cdev_release(struct inod
Takashi Iwai b96bab
 	if (wq_shared(wq)) {
Takashi Iwai b96bab
 		idxd_device_drain_pasid(idxd, ctx->pasid);
Takashi Iwai b96bab
 	} else {
Takashi Iwai b96bab
-		if (device_pasid_enabled(idxd)) {
Takashi Iwai b96bab
+		if (device_user_pasid_enabled(idxd)) {
Takashi Iwai b96bab
 			/* The wq disable in the disable pasid function will drain the wq */
Takashi Iwai b96bab
 			rc = idxd_wq_disable_pasid(wq);
Takashi Iwai b96bab
 			if (rc < 0)
Takashi Iwai b96bab
--- a/drivers/dma/idxd/device.c
Takashi Iwai b96bab
+++ b/drivers/dma/idxd/device.c
Takashi Iwai b96bab
@@ -962,7 +962,7 @@ static int idxd_wqs_setup(struct idxd_de
Takashi Iwai b96bab
 		if (!wq->group)
Takashi Iwai b96bab
 			continue;
Takashi Iwai b96bab
 
Takashi Iwai b96bab
-		if (wq_shared(wq) && !device_swq_supported(idxd)) {
Takashi Iwai b96bab
+		if (wq_shared(wq) && !wq_shared_supported(wq)) {
Takashi Iwai b96bab
 			idxd->cmd_status = IDXD_SCMD_WQ_NO_SWQ_SUPPORT;
Takashi Iwai b96bab
 			dev_warn(dev, "No shared wq support but configured.\n");
Takashi Iwai b96bab
 			return -EINVAL;
Takashi Iwai b96bab
@@ -1267,7 +1267,7 @@ int __drv_enable_wq(struct idxd_wq *wq)
Takashi Iwai b96bab
 
Takashi Iwai b96bab
 	/* Shared WQ checks */
Takashi Iwai b96bab
 	if (wq_shared(wq)) {
Takashi Iwai b96bab
-		if (!device_swq_supported(idxd)) {
Takashi Iwai b96bab
+		if (!wq_shared_supported(wq)) {
Takashi Iwai b96bab
 			idxd->cmd_status = IDXD_SCMD_WQ_NO_SVM;
Takashi Iwai b96bab
 			dev_dbg(dev, "PASID not enabled and shared wq.\n");
Takashi Iwai b96bab
 			goto err;
Takashi Iwai b96bab
--- a/drivers/dma/idxd/idxd.h
Takashi Iwai b96bab
+++ b/drivers/dma/idxd/idxd.h
Takashi Iwai b96bab
@@ -241,6 +241,7 @@ enum idxd_device_flag {
Takashi Iwai b96bab
 	IDXD_FLAG_CONFIGURABLE = 0,
Takashi Iwai b96bab
 	IDXD_FLAG_CMD_RUNNING,
Takashi Iwai b96bab
 	IDXD_FLAG_PASID_ENABLED,
Takashi Iwai b96bab
+	IDXD_FLAG_USER_PASID_ENABLED,
Takashi Iwai b96bab
 };
Takashi Iwai b96bab
 
Takashi Iwai b96bab
 struct idxd_dma_dev {
Takashi Iwai b96bab
@@ -471,9 +472,20 @@ static inline bool device_pasid_enabled(
Takashi Iwai b96bab
 	return test_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
Takashi Iwai b96bab
 }
Takashi Iwai b96bab
 
Takashi Iwai b96bab
-static inline bool device_swq_supported(struct idxd_device *idxd)
Takashi Iwai b96bab
+static inline bool device_user_pasid_enabled(struct idxd_device *idxd)
Takashi Iwai b96bab
 {
Takashi Iwai b96bab
-	return (support_enqcmd && device_pasid_enabled(idxd));
Takashi Iwai b96bab
+	return test_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
Takashi Iwai b96bab
+}
Takashi Iwai b96bab
+
Takashi Iwai b96bab
+static inline bool wq_pasid_enabled(struct idxd_wq *wq)
Takashi Iwai b96bab
+{
Takashi Iwai b96bab
+	return (is_idxd_wq_kernel(wq) && device_pasid_enabled(wq->idxd)) ||
Takashi Iwai b96bab
+	       (is_idxd_wq_user(wq) && device_user_pasid_enabled(wq->idxd));
Takashi Iwai b96bab
+}
Takashi Iwai b96bab
+
Takashi Iwai b96bab
+static inline bool wq_shared_supported(struct idxd_wq *wq)
Takashi Iwai b96bab
+{
Takashi Iwai b96bab
+	return (support_enqcmd && wq_pasid_enabled(wq));
Takashi Iwai b96bab
 }
Takashi Iwai b96bab
 
Takashi Iwai b96bab
 enum idxd_portal_prot {
Takashi Iwai b96bab
--- a/drivers/dma/idxd/init.c
Takashi Iwai b96bab
+++ b/drivers/dma/idxd/init.c
Takashi Iwai b96bab
@@ -512,18 +512,15 @@ static int idxd_probe(struct idxd_device
Takashi Iwai b96bab
 	dev_dbg(dev, "IDXD reset complete\n");
Takashi Iwai b96bab
 
Takashi Iwai b96bab
 	if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM) && sva) {
Takashi Iwai b96bab
-		rc = iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA);
Takashi Iwai b96bab
-		if (rc == 0) {
Takashi Iwai b96bab
-			rc = idxd_enable_system_pasid(idxd);
Takashi Iwai b96bab
-			if (rc < 0) {
Takashi Iwai b96bab
-				iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
Takashi Iwai b96bab
-				dev_warn(dev, "Failed to enable PASID. No SVA support: %d\n", rc);
Takashi Iwai b96bab
-			} else {
Takashi Iwai b96bab
-				set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
Takashi Iwai b96bab
-			}
Takashi Iwai b96bab
-		} else {
Takashi Iwai b96bab
-			dev_warn(dev, "Unable to turn on SVA feature.\n");
Takashi Iwai b96bab
-		}
Takashi Iwai b96bab
+		if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA))
Takashi Iwai b96bab
+			dev_warn(dev, "Unable to turn on user SVA feature.\n");
Takashi Iwai b96bab
+		else
Takashi Iwai b96bab
+			set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
Takashi Iwai b96bab
+
Takashi Iwai b96bab
+		if (idxd_enable_system_pasid(idxd))
Takashi Iwai b96bab
+			dev_warn(dev, "No in-kernel DMA with PASID.\n");
Takashi Iwai b96bab
+		else
Takashi Iwai b96bab
+			set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
Takashi Iwai b96bab
 	} else if (!sva) {
Takashi Iwai b96bab
 		dev_warn(dev, "User forced SVA off via module param.\n");
Takashi Iwai b96bab
 	}
Takashi Iwai b96bab
@@ -561,7 +558,8 @@ static int idxd_probe(struct idxd_device
Takashi Iwai b96bab
  err:
Takashi Iwai b96bab
 	if (device_pasid_enabled(idxd))
Takashi Iwai b96bab
 		idxd_disable_system_pasid(idxd);
Takashi Iwai b96bab
-	iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
Takashi Iwai b96bab
+	if (device_user_pasid_enabled(idxd))
Takashi Iwai b96bab
+		iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
Takashi Iwai b96bab
 	return rc;
Takashi Iwai b96bab
 }
Takashi Iwai b96bab
 
Takashi Iwai b96bab
@@ -574,7 +572,8 @@ static void idxd_cleanup(struct idxd_dev
Takashi Iwai b96bab
 	idxd_cleanup_internals(idxd);
Takashi Iwai b96bab
 	if (device_pasid_enabled(idxd))
Takashi Iwai b96bab
 		idxd_disable_system_pasid(idxd);
Takashi Iwai b96bab
-	iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
Takashi Iwai b96bab
+	if (device_user_pasid_enabled(idxd))
Takashi Iwai b96bab
+		iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
Takashi Iwai b96bab
 }
Takashi Iwai b96bab
 
Takashi Iwai b96bab
 static int idxd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Takashi Iwai b96bab
@@ -693,7 +692,8 @@ static void idxd_remove(struct pci_dev *
Takashi Iwai b96bab
 	free_irq(irq_entry->vector, irq_entry);
Takashi Iwai b96bab
 	pci_free_irq_vectors(pdev);
Takashi Iwai b96bab
 	pci_iounmap(pdev, idxd->reg_base);
Takashi Iwai b96bab
-	iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA);
Takashi Iwai b96bab
+	if (device_user_pasid_enabled(idxd))
Takashi Iwai b96bab
+		iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA);
Takashi Iwai b96bab
 	pci_disable_device(pdev);
Takashi Iwai b96bab
 	destroy_workqueue(idxd->wq);
Takashi Iwai b96bab
 	perfmon_pmu_remove(idxd);
Takashi Iwai b96bab
--- a/drivers/dma/idxd/sysfs.c
Takashi Iwai b96bab
+++ b/drivers/dma/idxd/sysfs.c
Takashi Iwai b96bab
@@ -588,7 +588,7 @@ static ssize_t wq_mode_store(struct devi
Takashi Iwai b96bab
 	if (sysfs_streq(buf, "dedicated")) {
Takashi Iwai b96bab
 		set_bit(WQ_FLAG_DEDICATED, &wq->flags);
Takashi Iwai b96bab
 		wq->threshold = 0;
Takashi Iwai b96bab
-	} else if (sysfs_streq(buf, "shared") && device_swq_supported(idxd)) {
Takashi Iwai b96bab
+	} else if (sysfs_streq(buf, "shared")) {
Takashi Iwai b96bab
 		clear_bit(WQ_FLAG_DEDICATED, &wq->flags);
Takashi Iwai b96bab
 	} else {
Takashi Iwai b96bab
 		return -EINVAL;