Commit 42a1b738 authored by Dave Jiang's avatar Dave Jiang Committed by Vinod Koul

dmaengine: idxd: Separate user and kernel pasid enabling

The idxd driver always gated the pasid enabling under a single knob and
this assumption is incorrect. The pasid used for kernel operation can be
independently toggled and has no dependency on the user pasid (and vice
versa). Split the two so they are independent "enabled" flags.
Signed-off-by: default avatarDave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/165231431746.986466.5666862038354800551.stgit@djiang5-desk3.ch.intel.comSigned-off-by: default avatarVinod Koul <vkoul@kernel.org>
parent b965182a
...@@ -99,7 +99,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp) ...@@ -99,7 +99,7 @@ static int idxd_cdev_open(struct inode *inode, struct file *filp)
ctx->wq = wq; ctx->wq = wq;
filp->private_data = ctx; filp->private_data = ctx;
if (device_pasid_enabled(idxd)) { if (device_user_pasid_enabled(idxd)) {
sva = iommu_sva_bind_device(dev, current->mm, NULL); sva = iommu_sva_bind_device(dev, current->mm, NULL);
if (IS_ERR(sva)) { if (IS_ERR(sva)) {
rc = PTR_ERR(sva); rc = PTR_ERR(sva);
...@@ -152,7 +152,7 @@ static int idxd_cdev_release(struct inode *node, struct file *filep) ...@@ -152,7 +152,7 @@ static int idxd_cdev_release(struct inode *node, struct file *filep)
if (wq_shared(wq)) { if (wq_shared(wq)) {
idxd_device_drain_pasid(idxd, ctx->pasid); idxd_device_drain_pasid(idxd, ctx->pasid);
} else { } else {
if (device_pasid_enabled(idxd)) { if (device_user_pasid_enabled(idxd)) {
/* The wq disable in the disable pasid function will drain the wq */ /* The wq disable in the disable pasid function will drain the wq */
rc = idxd_wq_disable_pasid(wq); rc = idxd_wq_disable_pasid(wq);
if (rc < 0) if (rc < 0)
......
...@@ -966,7 +966,7 @@ static int idxd_wqs_setup(struct idxd_device *idxd) ...@@ -966,7 +966,7 @@ static int idxd_wqs_setup(struct idxd_device *idxd)
if (!wq->group) if (!wq->group)
continue; continue;
if (wq_shared(wq) && !device_swq_supported(idxd)) { if (wq_shared(wq) && !wq_shared_supported(wq)) {
idxd->cmd_status = IDXD_SCMD_WQ_NO_SWQ_SUPPORT; idxd->cmd_status = IDXD_SCMD_WQ_NO_SWQ_SUPPORT;
dev_warn(dev, "No shared wq support but configured.\n"); dev_warn(dev, "No shared wq support but configured.\n");
return -EINVAL; return -EINVAL;
...@@ -1264,7 +1264,7 @@ int drv_enable_wq(struct idxd_wq *wq) ...@@ -1264,7 +1264,7 @@ int drv_enable_wq(struct idxd_wq *wq)
/* Shared WQ checks */ /* Shared WQ checks */
if (wq_shared(wq)) { if (wq_shared(wq)) {
if (!device_swq_supported(idxd)) { if (!wq_shared_supported(wq)) {
idxd->cmd_status = IDXD_SCMD_WQ_NO_SVM; idxd->cmd_status = IDXD_SCMD_WQ_NO_SVM;
dev_dbg(dev, "PASID not enabled and shared wq.\n"); dev_dbg(dev, "PASID not enabled and shared wq.\n");
goto err; goto err;
...@@ -1294,7 +1294,7 @@ int drv_enable_wq(struct idxd_wq *wq) ...@@ -1294,7 +1294,7 @@ int drv_enable_wq(struct idxd_wq *wq)
if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) { if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
int priv = 0; int priv = 0;
if (device_pasid_enabled(idxd)) { if (wq_pasid_enabled(wq)) {
if (is_idxd_wq_kernel(wq) || wq_shared(wq)) { if (is_idxd_wq_kernel(wq) || wq_shared(wq)) {
u32 pasid = wq_dedicated(wq) ? idxd->pasid : 0; u32 pasid = wq_dedicated(wq) ? idxd->pasid : 0;
......
...@@ -239,6 +239,7 @@ enum idxd_device_flag { ...@@ -239,6 +239,7 @@ enum idxd_device_flag {
IDXD_FLAG_CONFIGURABLE = 0, IDXD_FLAG_CONFIGURABLE = 0,
IDXD_FLAG_CMD_RUNNING, IDXD_FLAG_CMD_RUNNING,
IDXD_FLAG_PASID_ENABLED, IDXD_FLAG_PASID_ENABLED,
IDXD_FLAG_USER_PASID_ENABLED,
}; };
struct idxd_dma_dev { struct idxd_dma_dev {
...@@ -469,9 +470,20 @@ static inline bool device_pasid_enabled(struct idxd_device *idxd) ...@@ -469,9 +470,20 @@ static inline bool device_pasid_enabled(struct idxd_device *idxd)
return test_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags); return test_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
} }
static inline bool device_swq_supported(struct idxd_device *idxd) static inline bool device_user_pasid_enabled(struct idxd_device *idxd)
{ {
return (support_enqcmd && device_pasid_enabled(idxd)); return test_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
}
static inline bool wq_pasid_enabled(struct idxd_wq *wq)
{
return (is_idxd_wq_kernel(wq) && device_pasid_enabled(wq->idxd)) ||
(is_idxd_wq_user(wq) && device_user_pasid_enabled(wq->idxd));
}
static inline bool wq_shared_supported(struct idxd_wq *wq)
{
return (support_enqcmd && wq_pasid_enabled(wq));
} }
enum idxd_portal_prot { enum idxd_portal_prot {
......
...@@ -512,18 +512,15 @@ static int idxd_probe(struct idxd_device *idxd) ...@@ -512,18 +512,15 @@ static int idxd_probe(struct idxd_device *idxd)
dev_dbg(dev, "IDXD reset complete\n"); dev_dbg(dev, "IDXD reset complete\n");
if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM) && sva) { if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM) && sva) {
rc = iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA); if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA))
if (rc == 0) { dev_warn(dev, "Unable to turn on user SVA feature.\n");
rc = idxd_enable_system_pasid(idxd); else
if (rc < 0) { set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
dev_warn(dev, "Failed to enable PASID. No SVA support: %d\n", rc); if (idxd_enable_system_pasid(idxd))
} else { dev_warn(dev, "No in-kernel DMA with PASID.\n");
else
set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags); set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
}
} else {
dev_warn(dev, "Unable to turn on SVA feature.\n");
}
} else if (!sva) { } else if (!sva) {
dev_warn(dev, "User forced SVA off via module param.\n"); dev_warn(dev, "User forced SVA off via module param.\n");
} }
...@@ -561,6 +558,7 @@ static int idxd_probe(struct idxd_device *idxd) ...@@ -561,6 +558,7 @@ static int idxd_probe(struct idxd_device *idxd)
err: err:
if (device_pasid_enabled(idxd)) if (device_pasid_enabled(idxd))
idxd_disable_system_pasid(idxd); idxd_disable_system_pasid(idxd);
if (device_user_pasid_enabled(idxd))
iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA); iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
return rc; return rc;
} }
...@@ -574,6 +572,7 @@ static void idxd_cleanup(struct idxd_device *idxd) ...@@ -574,6 +572,7 @@ static void idxd_cleanup(struct idxd_device *idxd)
idxd_cleanup_internals(idxd); idxd_cleanup_internals(idxd);
if (device_pasid_enabled(idxd)) if (device_pasid_enabled(idxd))
idxd_disable_system_pasid(idxd); idxd_disable_system_pasid(idxd);
if (device_user_pasid_enabled(idxd))
iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA); iommu_dev_disable_feature(dev, IOMMU_DEV_FEAT_SVA);
} }
...@@ -691,6 +690,7 @@ static void idxd_remove(struct pci_dev *pdev) ...@@ -691,6 +690,7 @@ static void idxd_remove(struct pci_dev *pdev)
free_irq(irq_entry->vector, irq_entry); free_irq(irq_entry->vector, irq_entry);
pci_free_irq_vectors(pdev); pci_free_irq_vectors(pdev);
pci_iounmap(pdev, idxd->reg_base); pci_iounmap(pdev, idxd->reg_base);
if (device_user_pasid_enabled(idxd))
iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA); iommu_dev_disable_feature(&pdev->dev, IOMMU_DEV_FEAT_SVA);
pci_disable_device(pdev); pci_disable_device(pdev);
destroy_workqueue(idxd->wq); destroy_workqueue(idxd->wq);
......
...@@ -588,7 +588,7 @@ static ssize_t wq_mode_store(struct device *dev, ...@@ -588,7 +588,7 @@ static ssize_t wq_mode_store(struct device *dev,
if (sysfs_streq(buf, "dedicated")) { if (sysfs_streq(buf, "dedicated")) {
set_bit(WQ_FLAG_DEDICATED, &wq->flags); set_bit(WQ_FLAG_DEDICATED, &wq->flags);
wq->threshold = 0; wq->threshold = 0;
} else if (sysfs_streq(buf, "shared") && device_swq_supported(idxd)) { } else if (sysfs_streq(buf, "shared")) {
clear_bit(WQ_FLAG_DEDICATED, &wq->flags); clear_bit(WQ_FLAG_DEDICATED, &wq->flags);
} else { } else {
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment