dmaengine: idxd: don't load pasid config until needed
authorDave Jiang <dave.jiang@intel.com>
Thu, 7 Apr 2022 18:28:28 +0000 (11:28 -0700)
committerVinod Koul <vkoul@kernel.org>
Mon, 11 Apr 2022 11:58:58 +0000 (17:28 +0530)
The driver currently programs the system pasid to the WQ preemptively when
system pasid is enabled. Given that a dwq will reprogram the pasid and
possibly a different pasid, the programming is not necessary. The pasid_en
bit can be set for swq as it does not need pasid programming but
needs the pasid_en bit. Remove system pasid programming on device config
write. Add pasid programming for kernel wq type on wq driver enable. The
char dev driver already reprograms the dwq on ->open() call so there's no
change.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/164935607115.1660372.6734518676950372366.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/dma/idxd/device.c
drivers/dma/idxd/registers.h

index 3061fe8..2903f8b 100644 (file)
@@ -299,24 +299,46 @@ void idxd_wqs_unmap_portal(struct idxd_device *idxd)
        }
 }
 
-int idxd_wq_set_pasid(struct idxd_wq *wq, int pasid)
+static void __idxd_wq_set_priv_locked(struct idxd_wq *wq, int priv)
 {
        struct idxd_device *idxd = wq->idxd;
-       int rc;
        union wqcfg wqcfg;
        unsigned int offset;
 
-       rc = idxd_wq_disable(wq, false);
-       if (rc < 0)
-               return rc;
+       offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_PRIVL_IDX);
+       spin_lock(&idxd->dev_lock);
+       wqcfg.bits[WQCFG_PRIVL_IDX] = ioread32(idxd->reg_base + offset);
+       wqcfg.priv = priv;
+       wq->wqcfg->bits[WQCFG_PRIVL_IDX] = wqcfg.bits[WQCFG_PRIVL_IDX];
+       iowrite32(wqcfg.bits[WQCFG_PRIVL_IDX], idxd->reg_base + offset);
+       spin_unlock(&idxd->dev_lock);
+}
+
+static void __idxd_wq_set_pasid_locked(struct idxd_wq *wq, int pasid)
+{
+       struct idxd_device *idxd = wq->idxd;
+       union wqcfg wqcfg;
+       unsigned int offset;
 
        offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_PASID_IDX);
        spin_lock(&idxd->dev_lock);
        wqcfg.bits[WQCFG_PASID_IDX] = ioread32(idxd->reg_base + offset);
        wqcfg.pasid_en = 1;
        wqcfg.pasid = pasid;
+       wq->wqcfg->bits[WQCFG_PASID_IDX] = wqcfg.bits[WQCFG_PASID_IDX];
        iowrite32(wqcfg.bits[WQCFG_PASID_IDX], idxd->reg_base + offset);
        spin_unlock(&idxd->dev_lock);
+}
+
+int idxd_wq_set_pasid(struct idxd_wq *wq, int pasid)
+{
+       int rc;
+
+       rc = idxd_wq_disable(wq, false);
+       if (rc < 0)
+               return rc;
+
+       __idxd_wq_set_pasid_locked(wq, pasid);
 
        rc = idxd_wq_enable(wq);
        if (rc < 0)
@@ -797,7 +819,7 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
         */
        for (i = 0; i < WQCFG_STRIDES(idxd); i++) {
                wq_offset = WQCFG_OFFSET(idxd, wq->id, i);
-               wq->wqcfg->bits[i] = ioread32(idxd->reg_base + wq_offset);
+               wq->wqcfg->bits[i] |= ioread32(idxd->reg_base + wq_offset);
        }
 
        if (wq->size == 0 && wq->type != IDXD_WQT_NONE)
@@ -813,14 +835,8 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
        if (wq_dedicated(wq))
                wq->wqcfg->mode = 1;
 
-       if (device_pasid_enabled(idxd)) {
-               wq->wqcfg->pasid_en = 1;
-               if (wq->type == IDXD_WQT_KERNEL && wq_dedicated(wq))
-                       wq->wqcfg->pasid = idxd->pasid;
-       }
-
        /*
-        * Here the priv bit is set depending on the WQ type. priv = 1 if the
+        * The WQ 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
@@ -830,7 +846,6 @@ static int idxd_wq_config_write(struct idxd_wq *wq)
         * 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) {
@@ -1263,6 +1278,29 @@ int __drv_enable_wq(struct idxd_wq *wq)
                }
        }
 
+       /*
+        * In the event that the WQ is configurable for pasid and priv bits.
+        * For kernel wq, the driver should setup the pasid, pasid_en, and priv bit.
+        * However, for non-kernel wq, the driver should only set the pasid_en bit for
+        * shared wq. A dedicated wq that is not 'kernel' type will configure pasid and
+        * pasid_en later on so there is no need to setup.
+        */
+       if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) {
+               int priv = 0;
+
+               if (device_pasid_enabled(idxd)) {
+                       if (is_idxd_wq_kernel(wq) || wq_shared(wq)) {
+                               u32 pasid = wq_dedicated(wq) ? idxd->pasid : 0;
+
+                               __idxd_wq_set_pasid_locked(wq, pasid);
+                       }
+               }
+
+               if (is_idxd_wq_kernel(wq))
+                       priv = 1;
+               __idxd_wq_set_priv_locked(wq, priv);
+       }
+
        rc = 0;
        spin_lock(&idxd->dev_lock);
        if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags))
index aa642ae..02449aa 100644 (file)
@@ -353,6 +353,7 @@ union wqcfg {
 } __packed;
 
 #define WQCFG_PASID_IDX                2
+#define WQCFG_PRIVL_IDX                2
 #define WQCFG_OCCUP_IDX                6
 
 #define WQCFG_OCCUP_MASK       0xffff