dmaengine: idxd: fix setting up priv mode for dwq
authorDave Jiang <dave.jiang@intel.com>
Thu, 19 Aug 2021 16:34:06 +0000 (09:34 -0700)
committerVinod Koul <vkoul@kernel.org>
Sun, 29 Aug 2021 13:44:20 +0000 (19:14 +0530)
DSA spec says WQ priv bit is 0 if the Privileged Mode Enable field of the
PCI Express PASID capability is 0 and pasid is enabled. Make sure that the
WQCFG priv field is set correctly according to usage type. Reject config if
setting up kernel WQ type and no support. Also add the correct priv setup
for a descriptor.

Fixes: 484f910e93b4 ("dmaengine: idxd: fix wq config registers offset programming")
Cc: Ramesh Thomas <ramesh.thomas@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/162939084657.903168.14160019185148244596.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/Kconfig
drivers/dma/idxd/device.c
drivers/dma/idxd/dma.c
include/uapi/linux/idxd.h

index 87f2efb4fa65a97be4baff9ec28db4a1b28c6661..ca153384ebf08d74d3e9864521cd2cdae301c097 100644 (file)
@@ -285,6 +285,7 @@ config INTEL_IDXD
        tristate "Intel Data Accelerators support"
        depends on PCI && X86_64 && !UML
        depends on PCI_MSI
+       depends on PCI_PASID
        depends on SBITMAP
        select DMA_ENGINE
        help
index e093cf225a5c6a66cf673c57366511de856ab8ef..241df74fc0478330a26a11e8e3ae17ef23e750c9 100644 (file)
@@ -818,6 +818,15 @@ static int idxd_groups_config_write(struct idxd_device *idxd)
        return 0;
 }
 
+static bool idxd_device_pasid_priv_enabled(struct idxd_device *idxd)
+{
+       struct pci_dev *pdev = idxd->pdev;
+
+       if (pdev->pasid_enabled && (pdev->pasid_features & PCI_PASID_CAP_PRIV))
+               return true;
+       return false;
+}
+
 static int idxd_wq_config_write(struct idxd_wq *wq)
 {
        struct idxd_device *idxd = wq->idxd;
@@ -850,7 +859,6 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
        wq->wqcfg->wq_thresh = wq->threshold;
 
        /* byte 8-11 */
-       wq->wqcfg->priv = !!(wq->type == IDXD_WQT_KERNEL);
        if (wq_dedicated(wq))
                wq->wqcfg->mode = 1;
 
@@ -860,6 +868,25 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
                        wq->wqcfg->pasid = idxd->pasid;
        }
 
+       /*
+        * Here the priv bit is set depending on the WQ type. priv = 1 if the
+        * WQ type is kernel to indicate privileged access. This setting only
+        * matters for dedicated WQ. According to the DSA spec:
+        * If the WQ is in dedicated mode, WQ PASID Enable is 1, and the
+        * Privileged Mode Enable field of the PCI Express PASID capability
+        * is 0, this field must be 0.
+        *
+        * In the case of a dedicated kernel WQ that is not able to support
+        * the PASID cap, then the configuration will be rejected.
+        */
+       wq->wqcfg->priv = !!(wq->type == IDXD_WQT_KERNEL);
+       if (wq_dedicated(wq) && wq->wqcfg->pasid_en &&
+           !idxd_device_pasid_priv_enabled(idxd) &&
+           wq->type == IDXD_WQT_KERNEL) {
+               idxd->cmd_status = IDXD_SCMD_WQ_NO_PRIV;
+               return -EOPNOTSUPP;
+       }
+
        wq->wqcfg->priority = wq->priority;
 
        if (idxd->hw.gen_cap.block_on_fault &&
index 5c0a4d8a31f5e796a1cb79931b508832cec7c476..e0f056c1d1f565d09f0bb2e6b9d6a8e058dcb9c9 100644 (file)
@@ -69,7 +69,11 @@ static inline void idxd_prep_desc_common(struct idxd_wq *wq,
        hw->src_addr = addr_f1;
        hw->dst_addr = addr_f2;
        hw->xfer_size = len;
-       hw->priv = !!(wq->type == IDXD_WQT_KERNEL);
+       /*
+        * For dedicated WQ, this field is ignored and HW will use the WQCFG.priv
+        * field instead. This field should be set to 1 for kernel descriptors.
+        */
+       hw->priv = 1;
        hw->completion_addr = compl;
 }
 
index ca24c25252fbddf80ae808d75f789ca82c83470a..c750eac09fc9c446d6abcc60bde63253818e11c8 100644 (file)
@@ -27,6 +27,7 @@ enum idxd_scmd_stat {
        IDXD_SCMD_WQ_NO_SWQ_SUPPORT = 0x800c0000,
        IDXD_SCMD_WQ_NONE_CONFIGURED = 0x800d0000,
        IDXD_SCMD_WQ_NO_SIZE = 0x800e0000,
+       IDXD_SCMD_WQ_NO_PRIV = 0x800f0000,
 };
 
 #define IDXD_SCMD_SOFTERR_MASK 0x80000000